Code length dependent obfuscation

Wow, it’s been a long time! Hopefully I can find more time to blog over the next couple of months.

In any event, my paper from last year really could use some updates. Among other things there are a whole new slew of “Usual Suspect” vulnerabilities to document. For this post I’ll focus on documenting an interesting new exploit obfuscation technique I’ve run across recently -- code length dependent obfuscation.

Take a look at this obfuscated script from a malicious web site:

<script>
function x(UW,P)
{
   if(!P)
   {
      P=' [obfuscated data] ';
   }

   var W;
   var VM='';

   for(var G=0;G<UW.length;G+=arguments.callee.toString() .replace(/\s/g,'').length-535)
   {
      W=(P.indexOf(UW.charAt(G))&255)<<18|(P.indexOf(UW.charAt(G+1))&255)<<12|(P.indexOf(UW.charAt(G+2))&255)<<(arguments.callee.toString() .replace(/\s/g,'').length-533)|P.indexOf(UW.charAt(G+3))&255;VM+=String.fromCharCode((W&16711680)>>16,(W&65280)>>8,W&255);
   }

   eval(VM.substring(0,VM.length-(arguments.callee.toString() .replace(/\s/g,'').length-537)));
}

x(' [obfuscated data] ');

</script>

Note the use of arguments.callee.toString() . This effectively returns the text of the current script block. The script calculates the length of the text and actually uses this length to produce the correct de-obfuscated script to evaluate.

If you’ve read Analyzing Browser Based Vulnerability Exploitation Incidents then you already know how to replace the “eval()” statement in the script above with an alert() to get the de-obfuscated text without executing it. However as you can probably guess, the technique above defeats this trick because alert() is one character longer than eval().

This isn't hard to circumvent once you know what's going on. Simply change “eval” to “pval” and add the following script block before the primary script block on your test page:

<script>
function pval(e) { alert(e); }
</script>

Just make sure that the obfuscated script block itself doesn’t implement “pval” to try to trip you up!

Tip of the day: Try Prompt(0, [string] ) in place of alert( [string] ). This will allow you to easily copy de-obfuscated data to the clipboard.

Also, Rob Hensing let me know that pressing Ctrl-C on an alert() window will copy the contents of the alert box to the clipboard. Thanks Rob!