CVE-2014-1776: How Easy It Is To Attack These Days

This post originally appeared on

Just about a week ago, everyone was alarmed due to a new zero-day vulnerability affecting Internet Explorer 6 through 11. The vulnerability was used in attacks in the wild, which targeted IE 8 to IE 11. The impact was so severe that Microsoft hurried to issue an out-of-band patch. Today, I would like to show how relatively easy it is to attack these days, when you can just reuse code.

We will compare the attack that used CVE-2014-0322 (then, an IE zero-day) to the current attacks utilizing CVE-2014-1776. We will show an almost exact match between the two templates for the attacks, indicating that either the same group was behind the two campaigns, or that the ease of acquiring used exploit code (even from public sources) allows different groups to quickly reuse and adapt the same code to the next vulnerability.


Both attacks utilize use-after-free vulnerabilities in IE, and leverage Flash Player in order to easily bypass DEP and ASLR. In both cases the scheme is the same:

  • Load a Flash SWF file.
  • Spray the heap with ActionScript uint vector objects with 0x3FE elements, for a total of 0x1000 bytes (i.e., 1 page) of memory for each vector object (including the vector’s management information, which should be inaccessible directly from the ActionScript code).
  • Spray the heap with references to a Sound object, to be used later as the first trigger to the shellcode.
  • Call a JavaScript function in the HTML page and set a timer to invoke another AS function.
  • Trigger a UAF vulnerability using the JavaScript code, while spraying the heap in order to ensure that the used block is controlled.
  • Use the bug to change an AS vector’s size (which is inaccessible directly from AS).
  • Back in the timed function in the SWF, use the modified vector to change an adjacent vector’s size to encompass all virtual memory, effectively achieving full memory disclosure and writing abilities (where current permissions allow that).
  • Find a module in memory and reach NTDLL by hopping through modules’ import address tables.
  • Find a stack pivoting gadget in NTDLL as well as the address of ZwProtectVirtualMemory.
  • Overwrite the virtual function table pointer of the Sound object to initiate code execution by calling the Sound object’s (replaced) toString function. Then, use a few ROP gadgets to pivot the stack, change the permissions on the shellcode to RWX, and execute the shellcode.
  • Restore normal operation.

There are, however, some improvements in this CVE-2014-1776 attack over the CVE-2014-0322 attack. For example, while all the hard work is crammed into one big function in the CVE-2014-0322 attack, the authors of the CVE-2014-1776 attack strove for cleaner code and broke the huge pile of code into many smaller functions, which constitute basic primitives for the larger goal. In fact, now it is even easier to reuse this code for the next exploit…

The Flash Spray

In both cases vectors of uints are sprayed (with 0x3FE elements in each vector), as well as references to a Sound object. The values of the uints in the sprayed vectors are constructed so as to fit the address the attacker had chosen and the vulnerability (and the browser, if applicable).



The UAF Triggering

In both attacks, the JS code which triggers the vulnerability is called from the ActionScript code, using the external interface. The AS code then registers a function to be invoked at a later time and search for the artifacts of the triggered vulnerability. Although the code performing the actual UAF is almost the same, there are some differences in behavior here:

  • In the current attack, the JS function gets a parameter, which holds JavaScript code that is crucial for the vulnerability to arise. In contrast, in the previous attack, the entire JavaScript code was present in the HTML.
  • In the current attack, the JS code sent to the external function lies encrypted (using RC4) in the SWF file, and is decrypted only prior to sending it to the external interface. Other parts in the SWF (relating to the shellcode) are also encrypted. Consequently, if you only have the HTML file, you cannot reproduce the zero-day (and vice versa). In contrast, the previous attack had no encrypted elements at all.
  • In yet another effort to make sure the zero-day is not compromised even if one file falls into the wrong hands, in the current attack the HTML file was split into two files, the second one containing the JS code used for the heap-spray.

The heap-sprays, though, are very much alike.



Memory Ownage

In both cases this is pretty easy – look for the modified length of the vector (that is what the IE vulnerability was used for), use the modified vector to modify the adjacent vector’s length to span all memory, and use the second modified vector for memory read and write operations.



Looking for Modules and Functions

This is pretty straightforward – find a module in memory, go backwards to find its base, parse the PE header and look for a function imported from KERNEL32.DLL, repeat the same process to go from KERNEL32.DLL to NTDLL.DLL, and then parse its import table looking for the needed functions. However, the code for the recent attack has one improvement over the older code: The new code uses the Sound object’s vftable to get a function pointer which points inside the Flash OCX, while the older code scans the memory and tries to find an executable image by brute-forcing.



Running the Shellcode

In both cases, the Sound object’s vftable pointer is overwritten, pointing to a pre-crafted area in memory. Then, the Sound object’s toString method is called (#28 in the table), which runs a stack pivoting gadget chained to a gadget that uses ZwVirtualProtect on the shellcode, which immediately follows. The shellcode begins by saving information and restoring overwritten values.




We have shown a very high correlation between the exploit code used in the CVE-2014-1776 attack, and the exploit code used in the CVE-2014-0322 attack. Clearly, the same code base was used. Whether this is indicative of the same actor or not, we cannot tell, since all code was freely available on the net when the recent attack commenced.

Looking at the entire SWF file in both cases, it can be seen that some mistakes were made, and some code was copied without actually utilizing it or understanding why it is there. Nevertheless, the high correlation between the two exploits shows how easy it has become to reuse proven code from past exploits when preparing the next attack. This only means that organizations need to stay protected, as sophisticated attacks can be easily copied by teams who don’t possess the knowledge to construct such an attack on their own.

All endpoints on which Cyvera TRAPS was installed were (and are) protected from the CVE-2014-1776 attack: TRAPS stops this in-the-wild exploitation attempt at several different points. Since TRAPS does not rely on signatures or behaviors but on breaking the attacker’s core techniques, TRAPS stops even zero-day attacks (including this one) without any need for updates. Of course, TRAPS users were also protected from the CVE-2014-0322 attack.

Got something to say?

Get updates: Unit 42

Sign up to receive the latest news, cyber threat intelligence and research from Unit42