Today we will analyse a crash of Internet Explorer.
Reven scenario generation
According to Exodus Intelligence, a vulnerability was silently fixed in MS13-055 patch along with other things. They showed on their blog how to exploit it: http://blog.exodusintel.com/2013/11/26/browser-weakest-byte/.
We generated our REVEN scenario where we give an html file to Internet Explorer that triggers the vulnerable crash.
We let REVEN execute the scenario, and since IE stops by raising an exception we tell reven to stop analysing when it reaches the symbol KiUserExceptionDispatcher. After 30 minutes (more or less depending on the pc it ran on) we have our trace. It is about 10 069 180 sequences long (51 273 145 instructions, 52 028 972 with IRQ and page fault instructions).
At the end of the scenario we see the exception being raised after an invalid fault, when trying to dereference 0x10. This invalid address is calculated from a base pointer (likely that of a structure) which is null.
Now we will use REVEN’s built-in slicer script (it leverages its data tainting capabilities) to find out where this null pointer comes from. We configure it:
$ ./slicer.p Enter the initial sequence : 10069179 Enter the initial instruction : 1 Enter the ending sequence : 9819179 Enter the initialy tainted register [eax]: ecx
We ask it to operate up to 250 000 sequences back (around 1 000 000 instructions). Just to give you an idea it will take around 4 minutes when we wrote this article less than 2 seconds now. The time depends on how many operations are affected, on the kind of operation, etc…
You can see that the furthest point reached by the slicer is sequence #9819823, with xor ebx, ebx.
Browsing around this sequence in the gui, we see that the sequence right before is the destructor of the CHTMLEditor object.
Then, as shown in the slicer’s results, this zeroed ebx will be stored in the memory location 0x4ef8dc on sequence #9821517.
Allocations / Deallocations
We found our invalid dereferencing occurred on a piece of memory that depends on something that has been modified during a destruction. This is a hint that something might be wrong with allocations and deallocations, so let's explore that path.
REVEN is able to track all the allocations/deallocations, for now through the use of a script. Note: In the very near future we will integrate this features into the GUI and will make it also track the dereferencings so it knows about use after free, double free, etc. by default.
It tells us that the memory location 0x4ef8d0 was allocated at sequence #7051584 (the allocation had a size of 0xc8, so from 0x4ef8d0 to 0x4ef998). If we look 3 sequences later in the execution, at #7051587, we can see that we are in the constructor of the CSelectionManager() object, so we just constructed a CSelectionManager object.
This CSelectionManager object is then freed at sequence #9821532 and never reallocated after that.
But we know a dereferencing occurred at the address 0x4ef8dc, while executing the sequence #10069177. So here we have a case of use after free.
Timeline of the events
From the results of the slicer and of the allocation script we deduce this timeline:
#7051584 => allocation of 0x4ef8d0 to 0x4ef998 #9819823 => xor ebx, ebx #9821517 => mov DWORD PTR [esi+0xc], ebx // mov [0x4ef8dc], 0 #9821532 => free of 0x4ef8d0 #10069177 => mov eax, DWORD PTR [esi+0xc] // mov eax, [0x4ef8dc] #10069178 => mov esi, eax #10069179 => lea ecx, [esi+0x10] #10069179 => mov xxx, DWORD PTR[ecx] // deref of 0x10
Going to the first use after free
Now with the memory range history feature we will see all the accesses made to the CSelectionManager object by asking for all the operations that happened on the memory range 0x4fe8d0-4fe8998.
You can see that the first use after free in the CSelectionManager object occurs at #10068868, which is before the one that raises the exception at #10069177. This is pretty usual in use after free, race condition, etc.: the bug appears at one location but the software can crash much later. Here we see directly the first invalid behaviour of the program.
If we explore this first invalid access, we can see that edi has the 0x4ef8d0 value (in c++ it would be the this pointer), indeed we are in the method CSelectionManager::FireOnBeforeEditFocus(). The object tries to access to its data, but since the object was freed they can be either valid or not, and here the object apparently still has valid data.
At the previous sequence #10068867 we're returning from the function EdUtil::FireOnBeforeEditFocus().
REVEN’s “percent” feature can take us to the call corresponding to the ret instruction of the EdUtil::FireOnBeforeEditFocus().
We end up on the sequence #7965463, and the this pointer still points to the same object. We just jumped more than 2 000 000 sequences backward.
So our object called the method EdUtil::FireOnBeforeEditFocus() which took a path that lead to its destruction, and when returning from EdUtil::FireOnBeforeEditFocus() it was a freed object with invalid data.
Why did the CSelectionManager object get freed ?
Back to sequence #9821531 where the CSelectionManager object is freed, we can see that 8 sequences before the method CSelectionManager::Release() was called. With both the symbol being CSelectionManager::Release() and the instruction dec DWORD PTR[ecx+0x8] inside the sequence, it looks like the reference counter of the object is stored at 0x4ef8d4.
If we double click on the operand dword ptr[ecx+0x8] of the instruction dec DWORD PTR[ecx+0x8], a link will pop allowing us to go directly on the memory location pointed by this operand 0x23:0x4ef8d8. Then if we ask for the history of this memory location we can see every inc and dec on the reference counter.
Now between #7965463 (where CSelectionManager::FireOnBeforeEditFocus() is called) and #10068867 (where CSelectionManager::FireOnBeforeEditFocus() returns) there are 7 writes to this location, and the value of the ref count is 1 at the call.
The two firsts are CTask::AddRef(), they increment the ref count; the 3rd and 4th comes from CEditTracker::WeOwnSelectionServices(), they decrement the ref count.
Example of a AddRef() with the memory history :
So after those we’re left with a ref count equals to 1.
The last and interesting one is triggered by the destructor of the CHTMLEditor() object at #9821518.
So the destruction of the CHTMLEditor object caused a decrement in the reference counter of the CSelectionManager object which leads to the destruction of the CSelectionManager.
We could go further in the analysis and try to figure out why the CHTMLEditor object got freed, but the goal of this article is to show you some of REVEN’s features, so we'll stop here.
We just saw an example of crash analysis for Internet Explorer. We started with an invalid exception code and went to the invalid dereferencing using the many features of REVEN such as the slicer & data tainting that led us back to the destructor of the CHTMLEditor object, the memory history which showed us the uses after free of the CSelectionManager object that didn’t cause crashes and the accesses to its reference counter, the visual studio name demangling which helped us understand where we are in the code, the percent feature which helped us travel back and forth fast in the trace, etc.
I hope you enjoyed this article. If you have any technical question you are welcome to post a comment.