Wednesday, July 23, 2008

Pwning Javascript Malware: a soup to nuts approach

First some words of caution. This will (or should) set off any anti-virus software you have running on your machine. Also, this is live malicious code so please don't run it... and is the reason we use Linux to poke at this stuff. Again, live + malicious = bad so don't run it.


It seems other than a handful of ISC posts, javascript de-obfuscation references are few and far between. So taking what ISC and others have started, and maybe finished privately (just think if you shared we wouldn't be having this talk now, and I could have watched more episodes of BSG), we have constructed our own process of malware de-obfuscation. Don't worry this won't be a lame tutorial on how to hex decode something, or look you can change eval(unescape("...")); to document.write(unescape("...")). This will give an overview of looking at multiple levels of obfuscation using arguments.callee written specifically for Internet Explorer. So where's the "amazing" part? I'm going to tell you how to do it with SpiderMonkey on Linux.

A quick rundown of things you will need:


  1. SpiderMonkey patched to print eval(), but I'll show you why that's not necessary any more
  2. mystubs.js and mypost.js available here
  3. This script to emulate Internet Explorer's arguments.callee functionality
  4. A version of Chaosreader patched to do de-chunking (if you're getting this stuff from a chunked session)
  5. Some sort of text editor
  6. And the Javascript you want to de-obfuscate

If you can't find some malicious Javascript to de-obfuscate, you can download our example and follow along. The password for the zip file is 'pwned'.

After downloading the Javascript (evil.js from the zip file) open it up in your editor and add the following to the top:



window="";
window.location="/";
location="";
location.href="http://tag58.com/cgi-bin/index.cgi?ad";

This will allow us to fake the necessary information back to SpiderMonkey as to what objects the page has and where the page is located (in this case tag58.com).


Now we want to get the Javascript prepared for reversing. If you notice in this specific example it uses arguments.callee, then does a toString() and then gets the length. You will also notice that it concatenates the location.href to arguments.callee.toString(). So, how do we bypass all of these different tamper-resistant techniques? Simple, we use the script that emulates the IE version of arguments.callee.toString(). Copy and paste the entire function, from the first 'f' to the last '}', into a new document. Then without adding any spaces copy the http://...ad from above immediately after, save and exit (step2.js from the zip file). Finally run the script on the file you just created and note the output (which output is used depends on where in the script you want to inject it).


Now look for the part in the script that says TngP47fdn = TngP47fdn.toUpperCase(); and change that to TngP47fdn = "<output>"; Where <output> is the last bit from the script under [toUpperCase()]: (step2-function.js). Producing the file step3.js. This next part is the cool part. You can go through the trouble of patching SpiderMonkey to print out all calls to eval() or since you've subverted the tamper-resistant technique you can change them all to document.write(), *TaDa* To do this change the portion in the code from wegif4kx2(nmyWKuRI4) to document.write(nmyWKuRI4), and you'll notice all of the goodness being spewed forth when you run <path>/js -f <path>/mystubs.js -f step4.js -f <path>/mypost.js. As a side note, you can now put random code in the Javascript in the step4.js if you want to further debug the code to figure out how exactly the de-obfuscation routine works because by patching in the expected results the script doesn't know any better.


Simply wash, rinse and repeat until you get the meaty-goodness. I've tried this on quite a few of the samples I was able to get a hold of, and it has worked, but if you try it and it doesn't work let me know.

1 comment:

|)own wit know|3dg3 said...

oh noez! errr, ummm, pleez expanse...