Security Research
Showing results for 
Search instead for 
Do you mean 

The mechanism behind Internet Explorer CVE-2014-1776 exploits

Matt_Oh ‎05-14-2014 05:49 PM - edited ‎05-15-2014 12:43 AM

Recently Microsoft patched an Internet Explorer use-after-free bug (CVE-2014-1776) that was being exploited in the wild. Since then I’ve seen several reports of new variants based on the original exploit appearing ITW. Let’s look deep inside the exploitation mechanism to see how it works to make a use-after-free execute shellcode.

The whole exploit is made up of three parts. (Figure 1) The entry HTML is where the victim first visits when he receives a phishing email and clicks the link. The HTML loads a SWF file that performs a heap spraying operation. It calls back a Javascript function with de-obfuscated exploit Javascript code and the code manipulates the DOM structure of the main HTML file to trigger a use-after-free bug.



Figure 1 Exploit components



First things first, before the exploit actually triggers the vulnerability, it sprays the array of the heap with a Vector of uint type. The Vector is filled with various uint values. (Figure 2)


Figure 2 Heap spray code from SWF component


You can see the memory structure in Figure 3. The “this.s” array has 90466 members. Each array member is a type of Vector<uint> and each Vector size is 1022. The memory layout of this Vector<uint> data is simply represented by the following:


       Vector size (4 bytes) + extra header (4bytes)  + uint (4 bytes) array of 1022


So, basically by using an ActionScript data type of Vector<uint> and its assignment operations, you can interact directly with the actual memory content.


Figure 3 Heap spray structure


When I debugged the Internet Explorer process with this heap spray code running, I observed huge memory blocks allocated after the heap spray operation. (Figure 4) I ran the “!address” Windbg command before and after the heap spray operation and ran windiff.exe to diff the output from the command. The areas with a yellow background are all heap sprayed areas. As the heap spray elements are aligned by 0x1000 and the whole heap spray area is relatively big, it is usually assumed that the target memory block that the exploit uses (0x18090000~0x18290000) is almost always allocated. The other parts of the exploit assume that this area is allocated and use fixed addresses. As each array member has exactly the same contents and is aligned by 0x1000 bytes, you can assume that the exploit code later always sees the same data from this specific memory area if you access 0x1000 bytes aligned addresses.


Figure 4 Heap spray area diff




The vulnerability is a use-after-free bug. The CMarkup object is passed to CMarkup::OnCssChange method. (Figure 5)



Figure 5 Call stack of CMarkup method call


The CMarkup object passed to this method looks like Figure 6. The first DWORD from a normal C++ object usually points to vftable and the figure shows the valid one.


Figure 6 CMarkup object


This object is later freed when the destructor is called. (Figure 7)  This is related to how the object is referenced from other objects and how it is managed when the object is not used anymore. Note that the stack trace is actually overly long and we removed the parts that were nonessential.



Figure 7 Part of call stack when free of the CMarkup object happens


Just after the free operation is called upon the object, the memory is re-allocated as a string buffer when a Javascript string operation is called. (Figure 8) From the call stack, the original CMarkup::OnCssChange call has not yet returned. The exploit code carefully allocates multiple 0x190 bytes (which happens to be the size of the affected CMarkup object) of memory for string assignments.


Figure 8 Part of call stack when memory overwrite occurs on freed object


After the string assignments, the freed object memory area is filled with data under the attacker’s control. (Figure 9)


Figure 9 Overwritten data of freed CMarkup object location



2 bytes memory overwrite

So now the attacker has made a fake CMarkup object. The method the attacker chooses next is interesting. From upon the member of the fake object, a house-keeping method (ClearRunCaches) is called later from the CMarkup::OnCssChange method. (Figure 10) This method accepts data of CElement pointer type as its 2nd argument (eax at 0x639DD46A in Figure 10).



Figure 10 eax is passed to ClearRunCaches method



From Figure 11, the eax (CElement *) actually comes from an edi pointer, which pointing to “this” object which is a type of CMarkup and points to the address already freed in this case. So as shown above, the attacker has full control of the memory location pointed to by edi. Figure 11 shows you how eax is calculated from this fake CMarkup object. Based on this code, the value of eax passed to ClearRunCaches is 0x18182124.


Figure 11 Calculating location of ClearRunCaches argument


The contents of this area are shown in Figure 12. This address is inside the heap spray area I mentioned previously. So the attacker also has full control of the data over there already.


Figure 12 CElement Object passed to ClearRunCaches


The fake CElement object is passed along multiple levels of call stack to reach the VoidCachedNodeInfo method. (Figure 13) The interesting instructions are located inside this method.


Figure 13 Call stack of VoidCachedNodeInfo


Figure 14 shows the part where the interesting instructions are located. It just takes ecx and performs OR operation with 0xFFFFFFFF on it, which always makes the ecx value 0xFFFFFFFF. The cx, which is now 0xFFFF is overwritten to esi+0x42 address.


Figure 14 2 byte overwrite instructions


The register esi actually points to the CElement object – 0xe8 location, which is 0x18182fbe. So the overwritten memory location is 0x18183000 (0x18182fbe+0x42). (Figure 15)


Figure 15 2byte overwriting instruction


Address 0x18183000 is special as the area is inside heap sprayed memory and the location is 0x1000 bytes aligned. All the Vector<uint> objects are 0x1000 aligned here. So any address with 0x1000 alignment will point to the Vector<uint> header location where meta-information on the data structure is saved. The first 4 bytes of the Vector structure happen to contain Vector length information. Figure 16 shows the modification of the Vector length from 0x3fe to 0xffff. This enables the ActionScript code to access areas outside of the designated memory region.



Figure 16 Vector length corruption


Additional vector length manipulation

By modifying the original Vector length from 0x3fe to 0xffff, it can access about 0xffff*4 bytes of memory. But, this is not enough to be utilized to perform code execution, especially when ASLR and DEP is in play. The exploit tries to modify an additional Vector object to make the length bigger. In this case, it carefully calculated the header location of an adjacent Vector object and modified the length value from 0x3fe to 0x3ffffff0. (Figure 17)  One uint type is 4 bytes long and the length is 0x3ffffff0, so it has read/write access to total of 0xffffffC0 bytes of memory. Now it almost has the full power to do whatever it wants to do on the process memory.




Figure 17 Additional Vector object length modification



To defeat DEP, it uses a ROP technique. First, it sprays the heap with object pointers. From the ActionScript it looks for this object pointer pattern from the heap location. (Figure 18)


Figure 18 Searching object


After the exploit finds the location of the pointer, it overwrites the location with the pointer to a fake object (0x18184100). (Figure 19)


Figure 19 Overwritten object pointer


Figure 20 shows the fake object filled with ROP code and shellcode. When the toString method is called, code pointed to by object+0x70 location is called. (0x76fcb050 at 0x18184170)


Figure 20 ROP code


The code pointed to by the toString method is at 0x76fcb050, which is inside the ntdll.dll file. (Figure 21) The code is relatively simple and just exchanges eax with the esp register value and returns. Register eax points to the start of the object when this code is called (which is 0x18184100 in this case). When the ret instruction is called it retrieves a return value from the esp register location (0x18184100) and jumps there. It jumps to the ntdll!ZwProtectVirtualMemory function location in this case.


Figure 21 Fake toString function


Figure 22 shows the fake stack when this ZwProtectVirtualMemory function is called. The first value is the next return address and after that, arguments for the ZwProtectVirtualMemory function follow. Basically it gives PAGE_EXECUTE_READWRITE(0x40) protection level to the memory area from 0x181840ec with a size of 0x300 bytes.



Figure 22 ZwProtectVirtualMemory arguments


The next step returns to the 0x1818411c location which is located after the ROP code. (Figure 23) The shellcode patches around the memory location it already corrupted and jumps to the next part of the shellcode.


Figure 23 Bootstrap shellcode


The next shellcode constructs a CONTEXT structure and runs the next shellcode by calling the SetThreadContext function. (Figure 23)


Figure 24 Next  shellcode with SetThreadContext


The main shellcode executed at this time has a more complicated structure and multiple subroutines. (Figure 25)


Figure 25 Main shellcode



The exploit found in the wild for CVE-2014-1776 looks very interesting. It exploits a use-after-free bug with very good control of code execution. ASLR and DEP can be easily defeated with a minor amount of heap spray (only around 16MB) and additional techniques. I tested multiple times, but the heap sprayed area always includes the target memory address region (address around 0x18180000). To defeat DEP, it used ROP and changed memory permissions with ZwProtectVirtualMemory. To construct the shellcode with proper API addresses, it used its ability to read full process memory. It parses the PE structure and finds main modules and function addresses from ActionScript code. Even though the full exploit package becomes convoluted in this way, the SWF component is highly portable and it can be easily used by other exploits. Not surprisingly, this exploitation method using Flash component has been used for a while as mentioned from Fireeye blog post.


Thanks to the following individuals for providing various samples for this research.

  • Bryan Burns & Brian Keefer from Proofpoint, Inc
  • Marion Marschalek from Cyphort
  • Matt Brooks

0 Kudos
About the Author


Twitter: @ohjeongwook .

27 Feb - 2 March 2017
Barcelona | Fira Gran Via
Mobile World Congress 2017
Hewlett Packard Enterprise at Mobile World Congress 2017, Barcelona | Fira Gran Via Location: Hall 3, Booth 3E11
Read more
Each Month in 2017
Software Expert Days - 2017
Join us online to talk directly with our Software experts during online Expert Days. Find information here about past, current, and upcoming Expert Da...
Read more
View all