Thursday, July 7, 2011

Post-mortem Analysis of a Use-After-Free Vulnerability (CVE-2011-1260)

Recently, I've been looking into the exploitation of use-after-free vulnerabilities. This class of bug is very application specific, but armed with just the right amount of knowledge these vulnerabilities can be exploited to bypass most modern OS exploit mitigations. After reading Nephi Johnson's (@d0c_s4vage) excellent article[1] on exploiting an IE use-after-free vulnerability, I decided to ride his coattails and show the steps I used to analyze his proof-of-concept crash code.

As shown in his blog post, here is Nephi's test case that crashes IE:
Internet Explorer crashes at mshtml!CElement::Doc+0x2

76c.640): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=004aedc0 ecx=004e00e9 edx=00000000 esi=0209e138 edi=00000000
eip=6d55c402 esp=0209e10c ebp=0209e124 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010246
6d55c402 8b5070          mov     edx,dword ptr [eax+70h] ds:0023:00000070=????????

Here is the order of execution leading to the crash:

6d58595a 8b0b            mov     ecx,dword ptr [ebx]
6d58595c e89f6afdff      call    mshtml!CElement::Doc (6d55c400)
6d55c400 8b01            mov     eax,dword ptr [ecx]
6d55c402 8b5070          mov     edx,dword ptr [eax+70h] ds:0023:00000070=????????
6d55c405 ffd2            call    edx

This is a classic C++ use-after-free vulnerability. IE is trying to call a function within a previously freed object's virtual function table. In the disassembly above, a pointer to some object [EBX] has a pointer to its virtual function table [ECX] that subsequently calls a function at offset 0x70 in its vftable [EAX+0x70].

What we need to find out is what type of object was freed and how many bytes get allocated for that object. That way, we can craft fake objects of that size (using javascript) whose vftable at offset 0x70 point to our shellcode.

Since mshtml!CTreeNode::ComputeFormats+0x42 points to the object in question (in EBX), I set a breakpoint in Windbg on that instruction and got the following:
As can be seen above, EBX points to a freed CObjectElement object. How can we know for sure that the object was freed and that it points to a CObjectElement object? Enabling the page heap and user stack traces of every call to malloc and free will do the trick. This technique also allows us to observe the size allocated to CObjectElement.
The size that gets allocated to the CObjectElement object is 0xE0. It is also handy to see the call stacks of what allocated and freed the object. The size allocated for the object was determined via dynamic analysis. There's more than one way to skin a cat though. The same information can be gleaned via static analysis. A brief glance of the mshtml!CObjectElement::CreateElement function (which was called in the call stack above) in IDA shows that 0xE0 bytes is allocated for CObjectElement.

According to the disassembly (for CObjectElement::CObjectElement), the actual size of the class is 0xDC. However, 0xE0 is allocated on the heap because the compiler rounded up the size to the nearest DWORD boundary.

Lastly, although it is not always necessary for exploitation, let's determine the actual function that should have been called at the time of the crash. This can be accomplished several ways in Windbg.
The function that should have been called was mshtml!CElement::SecurityContext.

So to refresh our memories, what was needed to begin exploiting a use-after-free bug?

1) The type of object referenced after being freed
2) The size allocated to the object

There is no magic command that will give you this information and as usual, there is always more than one way to obtain this information. The key is to understand what lead to the crash. The next step is to utilize javascript to declare string variables that will allocate fake objects in the heap that point to attacker controlled shellcode (via heap spraying). This can be accomplished reliably without needing to point to a typical address like 0x0C0C0C0C which serves as both an address in the heap and a NOP slide. More on that in a future blog post...


1. N. Johnson, "Insecticides don't kill bugs, Patch Tuesdays do,"
June 16, 2011,