Archived Blog

IE7 Zero Day Technical Analysis

12.15.2008 - 11:07 AM

Following our alert, we completed this analysis for the Zero Day attack. The exploit for this vulnerability has two parts:
A. JavaScript heap spray code and x86 shellcode
B. The XML/SPAN tag vulnerability

A. JavaScript heap spray code and x86 shellcode

Here we can see the first part of the attack from the script point of view:

And here we can see the result of the heap spray, from the memory point of view:

B. The XML/SPAN tag vulnerability

Let's move on to the second part: the exploit and the trigger. Here we can see the attacker add XML/SPAN tags:

This exploit uses the special character #2570; (hex:0x0a0a) to construct the value of SRC in the !CDATA Label. You may wonder why it uses #2570 when IE will process those XML/SPAN tags. It's because the exploit will release the memory block that contains these elements but continue referring to the block in the next process. With the lack of sanity checks, an object will get overwritten with the 0x0A0A0A0A value, and because the attacker sprays the heap, the address 0x0A0A0A0A will host the attacker shellcode.

Here we can see how the execution got redirected to the attacker shellcode:

2) Advanced shellcode

The shellcode used by the Zero Day is rather interesting. The ending payload is quite similar to any normal shellcode (download a file and execute it), but it also has some peculiarities.

Before it does anything fancy, the shellcode starts to allocate memory using the GlobalAlloc function. It allocates 0x2000 bytes onto the heap, and the shellcode makes a copy of itself onto the heap. Let's see what happens next.

2.1 - Hooks

The shellcode hooks a few Windows functions, such as UnhandledExceptionFilter, LdrShutdownThread, and the like. We had never seen public shellcode hooking Windows functions before, so this was a surprise. We were expecting a very simple download and execute shellcode.

In order to hook them, it uses the VirtualProtect function with the PAGE_EXECUTE_READWRITE parameter. By default, Windows functions are write-protected. Therefore, you need to change the rights in order to modify them. After the write access is enabled, the first instructions are overwritten, in order to install the hook. The injected code redirects the hooked functions to special handling routines. These routines are part of the shellcode, obviously. Once the function is patched, the PAGE rights are set back to their original value.

Here you can see the call to VirtualProtect:

After the rights have been modified, this piece of code is responsible for installing the hook:

This is the first hooked function, UnhandledExceptionFilter, after it has been patched:

If we follow the redirection code, we end up here:

Basically, if the UnhandledExceptionFilter function is executed, it returns 0x80040111. Two other functions are patched, including LdrShutdownThread.

2.2 - Checks for hooks

The shellcode also checks some of the API functions it is planning to call. In fact, it checks to see if those functions have been hooked already (possibly by some sandboxing product or any sort of monitoring program). As you can see below, one of the checked API functions is CreateProcessA:

This piece of code is looking to see whether the API function has been detoured. If the function has been patched, the shellcode executes embedded instructions, and then skips the first 5 bytes of the API and resumes execution from there. Basically, this technique is used to bypass the hooks that could have been inserted in the API function. It's also checking for nops (0x90) right after the first byte of the detour (0xE8 or 0xE9).

2.3 - UrlDownloadToCache

The shellcode also uses UrlDownloadToCache rather than the infamous UrlDownloadToFile. This is most likely done to escape any products that are monitoring or hooking this function, in order to log the URLs of the payload. This is a cheap attempt to bypass protection, and it probably works.

2.4 - CreateProcessA

In order to execute the downloaded file, it executes cmd /c. This is typical and nothing really exciting.

2.5 - LdrShutDownThread

As mentioned earlier, a few hooks are made by the shellcode. The LdrShutdownThread hook counts both processes and windows, and its EnumWindow CallBack is looking for the IEFrame class using the GetClassNameA API function. We haven't yet looked into the details, but this could be used to check whether the shellcode is being executed from the IE context, and not from some other applications (such as shellcode2exe).

2.6 - shdocvw ordinal 101

For this one, we are not quite sure about its goal. We have a few hypotheses, but the parameters used are not matching. Indeed, it's pushing EBX four times, and EBX is 0. This function is supposed to take only two different parameters. While researching, the only references we could find to that function were bugs in Wine and similar projects. One of our guesses was that it could be anti-Wine code, but we haven't tested this theory yet. We have some other ideas about it, but if you know for sure, you are invited to email us and share your thoughts.

2.7 - Last words on the shellcode

The shellcode is doing a few other things, but most of it is quite standard for shellcode. The most surprising pieces were the actual hook checks and the hooking function. This shellcode has its own GetProcAddress-like function, and it is using HASH to find which function it has to resolve. Typical shellcode.

Security Researchers: Jun Zhang and Nicolas Brulez

Bookmark This Post: