08 May 2009

Decoding Obfuscated JavaScript

Earlier today I got an instant message from a friend I haven’t talked to since 2003. Although normally I’d be pleased to hear from an old friend, the fact that the message contained nothing but a link to a web site in the .ru TLD made me suspicious.

Out of curiosity, I grabbed a copy of the page using curl, and then examined it using a text editor. This is the safest way I know of to investigate potentially-hostile web pages; even if the page exploits a flaw in your browser, chances are it’s not designed to exploit a bug in emacs or vi when it’s just being read locally. To no surprise at all, the page was nothing but a bit of JavaScript. (Which is a good reason to browse with something like NoScript enabled.)

Since I’ve just recently started to play around with JS, I thought it would be interesting to take the program apart and see what it does. For safety reasons and because I don’t want to give the malware authors any additional traffic, I’m not going to link to the original Russian site or actually host their index page, but in the interest of science, I’ve put it up on Pastebin for anyone who wishes to poke at. Just be careful and don’t run the thing outside of a sandbox.

Pastebin link to the page’s raw HTML.

They’ve done some (fairly trivial) obfuscation to hide the actual code by way of the two script elements on the page. The first <SCRIPT> defines a Decode function and includes the actual payload in a long string; the second <SCRIPT> calls the decoding function.

Their decoder:

function Decode()
{
    var temp = "", i, c = 0, out = "";
    var str = "60!33!68!79!67!84!89!...blahblahblah";
    l = str.length; 
    while (c <= str.length - 1) {
       while (str.charAt(c) != '!') {
          temp = temp + str.charAt(c++);
       }
       c++;
       out = out + String.fromCharCode(temp);
       temp = "";
   }
   document.write(out);
}
Decode();

Obviously I’ve truncated the value of str here for brevity; it’s several thousand bytes long. What we’re looking for – the actual, presumably-malicious code – is inside that string. There are a number of ways we could get at the contents, but since the malware authors have so helpfully supplied us with a decoder, why not use it? Of course, we don’t want to run it from within a browser, or using any of the online JS shells (which might – stupidly – run the code that’s being obfuscated), but the js CLI shell is a pretty safe option.

If we weren’t absolutely sure what the code was going to do when we ran it, we might want to take additional precautions, like running it inside a walled-off VM, but in this case the code to be executed is trivial.

In order to make Decode() run inside the js CLI shell instead of inside a browser’s JS environment, one small change is necessary: where the code above has document.write(out), we need to change this to a simple print(out). This writes the results to standard output when we run the decoder via js -f badscript.js > badscript.out or something similar.

What we’re left with after running this is the page that the hapless victim actually arrives at, but which the malware author attempted to hide inside the script.

I haven’t had a chance to step through the resulting page completely yet, but it seems like a mess of advertisements combined with scripts designed to make it impossible to close the page. I assume there’s probably more nastiness buried in it besides the obvious, however: since the link was sent to me automatically, it’s a good bet it has a way of propagating itself.

This entry was converted from an older version of the site; if desired, it can be viewed in its original format.