Threat Level: green Handler on Duty: Russell Eubanks

SANS ISC: Raising the bar: dynamic JavaScript obfuscation - SANS Internet Storm Center SANS ISC InfoSec Forums

Sign Up for Free!   Forgot Password?
Log In or Sign Up for Free!
Raising the bar: dynamic JavaScript obfuscation

Couple of days ago one of our readers, Daniel Kluge, pointed us to a web page with some heavily obfuscated JavaScript code. The operation was typical and consisted of a compromised site that had an obfuscated iframe which pointed to the final web site serving various exploits.

The obfuscation of the iframe was relatively simple but the second stage was more heavily obfuscated with some things we’ve never seen before.

After downloading the JavaScript file it was obvious that all function and variable names are complete random. Further to that, the deobfuscation function used the well known arguments.callee.toString() trick in order to prevent modification of the code (so you just can’t replace the final document.write() call to something else as this will break the deobfuscation function body – attempts such as this one typically throw the function into an endless loop).

The screenshot below shows how the function looked when I first retrieved it.

Obfuscated JavaScript function

Now, what makes this new is that the hosting web site generates this code dynamically! Every time you request this web page it will use completely random names for all variables and functions. As the deobfuscation function uses itself to deobfuscate the input, changing variable and function names even causes the payload information to change. Below you can see the beginning of the JavaScript file for two other subsequent retrievals:

(2nd try)

Obfuscated JavaScript function (2nd try)

(3rd try)

Obfuscated JavaScript function (3rd try)

The reason for doing this is obvious, such heavy obfuscation makes signature based detection much more difficult, if not impossible and it wasn’t surprising to see that 0 anti-virus programs detected this when tested on VirusTotal.

After deobfuscating the payload I found out that it contains the typical set of exploits: the ADODB vulnerability exploit (MS06-014), the QuickTime and WinZIP exploits, AOL SB.SuperBuddy.1, WebViewFolderIcon and the VML Element Integer Overflow . Finally, one new addition is the exploit for the NCTAudioFile2 ActiveX vulnerability ( While this is an old vulnerability dating from January 2007, a fully working exploit was publicly released in April and what’s worse is that the affected ActiveX control is delivered with dozens(!!!) of popular audio/video applications. This is shifting the patching process from the base OS to client applications which is usually much more difficult for users, especially if those applications don’t support automatic updates so it’s left up to the user to first find out that he has a vulnerable application and then manually patch it.

Browser differences

Now back to the infamous arguments.callee.toString() function.  For those of you who regularly read our diaries, you probably remember that I analyzed a similar obfuscation method back July 2006 ( The obfuscation function back there just used the length parameter to see if anything has been changed (obviously, changing the document.write() call to alert() or something similar will change the function body length as well). I found out that Internet Explorer and Mozilla treat white space differently and this caused the exploit to fail in Mozilla.

Daniel had problems deobfuscating this function initially and the reason why that happened wasn’t clear immediately because the deobfuscation function in this case does this:

var o3b522f35=arguments.callee.toString().replace(/\W/g,"").toUpperCase();

this call converts the function body to upper case and then strips all white space (\W matches all non-word characters) so the fact that Internet Explorer and Mozilla don’t calculate white space the same can’t matter here.

However, Daniel used Rhino while debugging it while I was playing with Windows debugging capabilities so we knew it had to be something related to the browser wars again.

After some investigation, Daniel found out that there are other inconsistencies between Internet Explorer and Mozilla when using the arguments.callee.toString() function. You can also test your browser with this bit of JavaScript code:

<script type="text/javascript">
function func(){
var l = arguments.callee.toString().replace(/\W/g,"").toUpperCa
var failme = 00001;
alert(l.length.toString() + ' Func: ' +l );}

This is a simple test – it calls the same function as the deobfuscation code and just declares one variable called failme with the value of 00001. If you want to test this, go to

Different browsers and different results:

  • Safari: 93
  • Firefox 2: 94
  • Internet Explorer 6 and 7: 98

Daniel’s observations were:

  • For some unknown reason Safari ignores “g” from the replace call. Why would they do that is not clear but it looks like a bug to me (“g” is definitely a word character).
  • All browsers but Internet Explorer strip leading zeros on integers so they treat variable “failme” as 1 when counting the number of characters; Internet Explorer actually counts 5 characters there.

This was the main reason why the deobfuscation function failed in Rhino which uses Mozilla’s JavaScript engine (so it stripped leading zeros from variables). Browsers are certainly strange beasts …




351 Posts
ISC Handler

Sign Up for Free or Log In to start participating in the conversation!