InfoSec Handlers Diary Blog

ASN.1 attacks are nothing new, neither is MS04-007. But they are still popular and I figure it may be interesting to look at a recent attack in a bit more detail and to show a couple tools to quickly figure out whats going on.

The traffic was collected at a development server of mine. It is connected to a cable modem via a firewall. The firewall logs every packet to/from the server which provides for nice detailed logs. I am only able to quote excerpts here as the packet is long/messy. In order to allow you to follow along, I made the packets of interest available here.

MS04-007 details a vulnerability in Microsoft's ASN.1 parser. This parser is used by a number of subsystems in Windows, one of which is the decoding of these authentication tokens. The same vulnerability can be exploited via SMB or HTTP, using essentially the same exploit. In the HTTP case, the exploit has to be Base64 encoded. Only after decoding the token is it passed to the vulnerable ASN.1 parser. So lets look at the decode of the authentication token. To decode it, I used a little perl script:

use MIME::Base64;print decode_base64("... long messy string... ==");

Sure, there are probably existing tools to decode this, but I try to limit the size of my tool box and tend to use these one liners for simple stuff like that.

Nice! We got the payload of the exploit nicely decoded without haveing to speak too much opcode. Essentially the exploit attempts to run 'ftp' on my system to pull a second stage from the infecting host. The IP address is not obfuscated here. I assume whoever wrote this particular bot messed up coding the source IP and ended up with 0.0.0.0. And ftp server was listening on port 24706 at the attacking host. But it appeared to be too busy to let me download 'Updater.exe'. The attacking host was notified and has been cleaned.

Now in this case, the target was an Apache web server. The corresponding access and error logs from this attacks are:

Note that this rule would not detect the particular version of the exploit shown here. If you run the packet capture posted above through snort, you will get however one alert from the http_inspect preprocessor:

Which would just look for overly long 'Authorization: Negotiate' lines. I split up the 'Authorization: Negotiate' string to allow for various spaces and such. "nocase" may be another option to chose to make this rule safer. The RFC at first glance does not specify a maximum length for the authentication tokens, so your mileage may vary. With http_inspect enabled, you will get two alerts. One from your rule, and one from http_inspect.

I guess it is safe to assume that the origin is not a 'Windows 98' machine as the client string suggests. The IP resolves to a server which identifies itself as 'Apache/1.3.31 (Unix)'.

Well, next time they come back I will have a dummy php script at these URLs to take a look what they are trying to acchieve. The program they are trying to exploit, phpMyChat, can be found here: http://www.phpheaven.net/phpmychat:home . The versions referenced about (14.2 and 14.5) came out in 2000 and 2001, so almost 5 years old now. The project looks a bit abandond.

If someone got details, let use know!Update: Our reader Toni pointed out that phpmychat has multiple file inclusion issues if "register_globals" is not disabled. He also found this vulnerability: http://www.securityfocus.com/bid/17382/info

We got a heads up today from one of our readers (thanks Oliver) that there is a newly discovered security issue with the mod_rewrite module in the Apache httpd server. The issue itself has been in the Apache httpd code for sometime, depending on which of the three version trees you are using. The vulnerability affects all three major version trees that Apache still supports (1.3, 2.0 and 2.2). From the release notes on Apache's web site:

CVE-2006-3747: An off-by-one flaw exists in the Rewrite module, mod_rewrite, as shipped with Apache 1.3 since 1.3.28, 2.0 since 2.0.46, and 2.2 since 2.2.0.

Although there are some conditions and restrictions on the specific combination of mod_rewrite directives that create the vulnerability, it is still recommended that anyone using the mod_rewrite module upgrade their Apache httpd installation sooner rather than later. If you are not using the mod_rewrite module, you are not vulnerable to this potential issue.

If you have installed the Apache httpd web server from a binary distibution from your vendor, please check your vendor's patch announcements and distribution sites to see when you will be able to install the newer version of the software which addresses the flaw.

Microsoft posted a blog entry this afernoon containing information about their assessment of recent reports of a vulnerability which was not addressed in MS06-035. It appears that the current proof of concept is limited to a denial of service attack and is not currently being observed as an attack vector. Microsoft reports that they have not identified any possibilities that the issue could allow remote code execution.

We recommend that you assess your particular situation. Blocking ports 135-139, 445 is already a best practice. Whitelist IPs that may need these ports, but remember to limit your exposure from your road warrior/home office users. We expect that Microsoft will release a patch on August 8 to address this current threat.

Juha-Matti dropped us a note to say that although the 1.5.0.5 version of Thunderbird (which fixes the Thunderbird vulnerabilities discussed here is not available on the Thunderbird web site it is available at this mirror site.

Update: (2006-07-28 19:50 UTC) 1.5.0.5 is now available at the main site above and will be automatically downloaded if you choose the "check for updates" from the Help menu.

Reader Gilbert sent us a link to a site that caused couple of alerts with his anti-virus program. Initially this looked like a typical web site hosting malware, but it turned out to be much more.

The HTML document was absolutely standard, except for one iframe which was, of course, hidden. This raised our eyebrows and we started following what turned out to be an interesting obfuscation.

Before we start with this we should stress out that, if you decide to do something similar, it is always recommended that you do this on an isolated machine ? virtual machines are ideal candidates for playing with malware of this type.

First Layer

The iframe pointed to a JavaScript file which used (today) more or less standard obfuscation: a function was defined with various permutations and it was called with a document.write at the end.The obfuscation typically looks like this:

As you can see, the dc() function is called with the encoded string, and document.write() is called at the end. This results in another JavaScript which is executed immediately after it's decoded by the document.write() call.Decoding this JavaScript is typically pretty easy and there are numerous ways of doing it. The easiest way of what's going is just to replace the document.write() call with the alert() call ? this will cause your browser to print the whole new code in an alert popup.If you want to be more creative, you can add code which will replace all < or > characters to something else ? this will cause your browser not to parse it as JavaScript.

Another nice trick is to add document.write("<textarea rows=100 cols=100>"); as first line after the script tag and document.write("</textarea>"); as last line. The decoded javascript will now show up nicely inside the text area which can be copy&pasted easy. Thanks to Tom and Johannes for this trick.

Second layer

So, once the first step was decoded we were greeted with another obfuscated code. This code looked similar to the previous one (but boy, we were wrong with that). This time the (de-)obfuscation function didn't end with a document.write() call, but with an eval() call. The eval() call evaluates a string and executes it as if it was script code. In other words, when obfuscating code, the eval() call is typically used to call some part of the existing code again.

This part is what caused us the most problems, and here's why. So, the deobfuscating code looks like this (non interesting parts have been removed):

So again, the function r() is called with a long ASCII string. There is a for loop which does various permutations and then an eval() is called. So, the first step we did here was to replace eval(ii) with alert(ii). That was easy enough but a surprise was waiting for us ? when we executed that we just got some binary output. Hmm, that can't be right.

After studying the permutation for loop a bit (permutations itself aren't interesting for us) we saw something interesting in the for loop definition itself. You can see that the sa variable is being increased in every step by something weird: sa+=arguments.callee.toString().length.

Now the whole night became very very interesting. Arguments.callee specifies the function body of the currently executing function! So this code actually uses itself to do the permutation ? if you change something in the code (like we did when we replaced the eval() call with alert()) you will break the whole deobfuscation part!

Firefox is not IE and vice versa

But, this is not the end of the story. In this case, the sa variable is being increased by the value which is calculated from the function string length (arguments.callee.toString().length returns the number which is the length of the whole function in characters) decreased by 444.So, if when replaced eval() with alert(), we added 1 character to the function length, so we had to increase this number to 445. Easy ? we changed that and started this in Mozilla and it didn't work again!

Two hours later (fast forward for you) we found a very interesting thing: Mozilla Firefox and Internet Explorer don't return same values when arguments.callee.toString().length is called on a function!This is easy to test if you want ? just create the following HTML file:

<html><head> <script type="text/javascript"> <!--

function func(){var l = arguments.callee.toString().length;alert(l);}

func(); //--> </script></head></html>

This JavaScript creates a function called func and then displays content of the variable "l" ? the content will be whatever the call arguments.callee.toString().length return.On our test machine, when this JavaScript is executed in Mozilla Firefox we get 81, while in Internet Explorer we get 69.Why this is happening is another story, so lets get back to our deobfuscation.

A recursive call

Knowing this we now know that our alert() call with increased number (444 to 445) was actually ok, but we have to execute this from Internet Explorer, or we have to calculate new numbers for Mozilla.We decided to use Internet Explorer (in a virtual machine, of course) and voila ? we got the eval() call content: it was another call to the r() function. Knowing how the r() function works, all we had to do was call it again and we got another obfuscated JavaScript (this is 4th step already).

This time, our job was easier. This part just consisted of an unescape() call. The unescape call basically has ASCII characters which are just shown as values. You can even "crack" this manually, but it is easier if you just assign this call to another variable and then display that with another alert() call.

After the unescape() call we were greeted with another obfuscation routine, which was simple this time ? it was actually very similar to the routine used in the first step, so all written above applied to this step as well.

The final result

And we finally arrived to the end of the whole (we caught the white rabbit). The final result was a bit disappointing at first ? it was another iframe to a PHP file.

That PHP file is exploit for MS06-014, RDS.Datastore data execution which dropped a downloader on the victim's machine. The downloader in turn downloaded second stage, which was a keylogger called Trojan.Anserin.

The dropped malware was more or less typical, but this was indeed a very interesting investigation, which taught us some new things about obfuscation which we haven't seen before.