Thursday, July 7, 2011

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.

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...

You Say: "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".

Where you you see that CObjectElement points to a freed object? The only free data i see is the VFTable of mshtml!CPhraseElement method:

You'll notice that the last object address before the crash is 00608808 which was used by some other object (mshtml!CPhraseElement) in this case. Notice that the last reference to address 00608808 referred to the CObjectElement instance.

The example that follows simply shows definitively that the address in EBX was actually freed before crashing. Enabling the page heap is what triggered the access violation.

Forgive me for gravedigging this, but if EBX (or any other general register) is an object pointer, is it always the case that the contents of EBX compose its VFTable pointer and that the contents of the VFTable pointer compose the VFTable itself? Otherwise, how did you determine the following for your breakpoint: