Security Research
Showing results for 
Search instead for 
Do you mean 

Technical Analysis of CVE-2014-0515 Adobe Flash Player Exploit

Matt_Oh ‎05-21-2014 02:08 PM - edited ‎05-23-2014 12:53 PM

At the end of April, Kaspersky reported an ITW exploit that was abusing an Adobe Flash Player zero-day vulnerability at the time (CVE-2014-0515). The vulnerability was known to be inside the Pixel Bender parser in Adobe Flash Player. I had time to look deeper into how the vulnerability works and how control of the code is acquired using this vulnerability.

Figure 1 shows the overall structure of the exploit sample I tested. I used the swfdump tool from swftools.  Tag 057 contains binary data that is used as Pixel Bender bytes later in ActionScript Byte Code (tag 052).


Figure 1 Overall structure of the exploit SWF file


Heap spray

As usual, the exploit starts with a heap spray. Similar to the exploit I discussed in my previous blog on the CVE-2014-1776 IE vulnerability, this one also uses the Vector data type to achieve fine control of memory layout and data. But there are a couple of differences to the method I described with the IE exploit.


Laying out memory

First, it sprays the heap with Vector.<int>  with a size of 0x22 (Figure 2). Each Vector.<int> has the following format:

       Vector size (4 bytes) + extra header (4bytes)  + int (4 bytes) array of 0x22


The vector is pushed as a member of the Array data type, and the size of the array becomes 0x10000.



Figure 2 Allocating 0x22 size of Vector.<int> array


Figure 3 shows the actual memory data when this heap spray occurs. Vector.<int> members are mostly adjacent to each other and have a size of 0x90 (8 bytes header + 4*0x22 bytes of int array).  The first 4 bytes of each member is 0x22 in DWORD, which indicates the Vector size.



Figure 3 Memory raw data for Vector.<int>



Making holes

Now that the basic layout of the heap spray is done, the exploit tries to shrink the size of each Vector to 0 (Figure 4). The way the Flash internal logic works makes holes between each members. Instead of allocating a new Vector array with size 0, it just re-uses previous memory layout resetting length field to 0.


Figure 4 Set vector lengths to 0


The result of this length reset is shown in Figure 5. The Vector size has shrunk to 0 and each Vector member uses only 8 bytes of memory, leaving an extra 0x88 bytes free for use. The size of 0x88 is very much intentional here and it becomes important later when the actual exploit happens.



Figure 5 Memory raw data for Vector.<int> after resetting length to 0



Making bigger holes


Aside from making 0x88 bytes of heap spray holes, the exploit tries to make more holes in parts of the heap spray area. (Figure 6) The whole creation works by assigning 0x100 length to some of the Vectors. This makes the existing array in the heap spray area to be freed and allocated in another place.


Figure 6 Increasing size of some array members



Figure 7 shows the memory layout before these holes are created. There are 0x88 bytes of freed memory.


Figure 7 Before increasing the array member size



When this additional hole creation happens, some parts of the heap area look like Figure 8. This makes 0x118 bytes of freed memory area in the heap spray region. I tested with the exploit and this bigger hole is essential to the exploit because during the exploit process, the code uses this empty area rather than creating new heap memory, and it is related to whether the previous smaller holes with 0x88 size are used further in the code.


Figure 8 After increasing the array member size


The vulnerability – Pixel Bender Parser Issue


First memory corruption

The vulnerability is inside the code where the Flash Player parses the Pixel Bender data from the exploit code. When I tested with a debugger, I found that the DWORD value at offset 0xEA of Pixel Bender data is responsible for triggering the vulnerability. (Figure 9)


Figure 9 Malformed Pixel Bender data triggers the vulnerability


To analyze how this memory region breaks Pixel Bender parsing code, I used the dpbj tool, which can be utilized to disassemble a raw Pixel Bender binary format file. The author has released the source code of the tool, aside from just the binary. I found this project very useful, particularly when there was no good public documentation on the internal format of a Pixel Bender binary available. Figure 10 shows the code where the memory area responsible is located.



Figure 10 Pixel Bender code triggers the vulnerability


The metadata  of defaultValue is intended to be just 4 bytes long, but the code tries to convert all of its 16 arguments and puts them in the memory array, incurring a memory corruption error. Figure 11 shows how the sel instruction and the defaultValue metadata is saved. The original binary data is parsed and translated into a bytecode that is later used for further operations. The 2nd value from the defaultValue argument overwrites the index value inside the sel instruction’s byte code in memory.


Figure 11 Memory corruption


The code that overwrites this sel instruction area is shown in Figure 12. The fstp instruction saves a value to a memory location designated by its operand. In this case, the original value of 0x000B3880 is saved directly to 0x000B3880 after endian change. The instruction at 0x167EC63 shows that the memory location will be increased by 0x14. The first defaultValue member falls inside a valid memory location but the values from the 2nd argument are inside the memory of the sel instruction’s byte code area.



Figure 12 Code responsible for memory corruption


Second memory corruption

The first memory corruption corrupts the other instruction’s byte code. The corrupt byte code is interpreted and run. Figure 13 shows the code that interprets the byte code op code.


Figure 13 Switch on op code


Figure 14 shows the code where each instruction’s operand is passed to the set_array_value function.


Figure 14 Code setting register values


The code that actually performs additional memory corruption is shown in Figure 15. The function is called for each instruction and when the corruption happens, the arg_index value is 0x000B3880 - which is from the corrupted memory area.  The index value is converted to an offset in the memory that is used later to save some data. From the instruction at 0x0167BC78, ecx is a pointer to a data structure on the memory and edi is an offset calculated from arg_index. The Eax value is a little bit tricky. The value is returned from a previous call to sub_1909EE0 which returns a pointer to a memory location.



Figure 15 Memory corruption code


An interesting thing happens here. From ecx (base pointer), edi (offset), and eax (value to overwrite), the attacker can control edi for sure. Also, as a consequence of using the previously mentioned heap spray technique, there are a lot of memory holes with size 0x88 on the heap. The data structure pointed to by ecx has a size smaller than 0x88 and there is a strong chance that the pointer will fall in one of the holes on the heap spray area. So, now the attacker can control ecx and edi somehow. But, eax can be a random (but valid) memory location on the heap. The attacker doesn’t have control of it. Here’s an interesting fact; the attacker doesn’t need to control eax. The fact that eax is always a valid pointer makes it a value bigger than some range of values (probably bigger than 0x22+1). Figure 16 shows the memory state just before this memory corruption occurs.



Figure 16 Base address points to one of the heap spray holes with size 0x88



Figure 17 shows the memory state when the memory corruption happened through the related instructions. You can see that the length field of a[x+1] is overwritten with a pointer value. The value can be random, but it is always bigger than 0x22+1. This makes it possible for the attacker to corrupt the next Vector’s length field.


Figure 17 After memory corruption, a[x+1].length will be a huge value




Additional Vector corruption

Now a[x+1].length becomes a huge value.  It can corrupt additional Vector elements and the exploit can have full access to process memory. It corrupts the next Vector’s length field to 0x40000001. (Figure 18)



Figure 18 ActionScript code to corrupt next vector's size to 0x40000001 (corrupt_index=x+1)


Now a[x+2].length becomes 0x40000001. Figure 19 shows the state when this additional corruption happens. From a[x+2], the exploit can use arbitrary index values to access any memory locations.


Figure 19 Memory state after additional Vector length corruption


FileReference spraying & corruption

The exploit creates 64 FileReference objects on the heap. (Figure 20)


Figure 20 Spraying FileReference objects


It searches for the FileReference objects from the heap using some conditions and when it finds one, it overwrites its function pointer. If we say v = a[x+2], then it will assign a v[2] address as the function pointer. The memory area around this fake function table is constructed from ActionScript, as shown in Figure 21.


Figure 21 Building a fake FileReference function table and arguments


Memory permission change

The exploit can now control data for the FileReference object’s function pointers. The exploit searches for the FileReference object on the heap area by heuristic method and when it locates one, it will replace the function table pointer address to a fake address. (Figure 22)



Figure 22 Modifying FileReference object function table pointer


Figure 23 shows the fake function table with fake arguments. The v[7] is the pointer where the cancel method is called. Figure 24 shows the ActionScript code that calls the cancel methods.



Figure 23 Fake FileRefence function table



Figure 24 Running the cancel method from the fake FileReference function table


The code pointed to by v[7] is shown in Figure 25. This function uses an argument from the function table pointer. The eax points to v[2] location when it is called. The instructions at 0x6EB8D5D8 and 0x6EBD5DB show that two arguments from eax-8 (v[0]) and eax-4 (v[1]) are used, which are interpreted as the size and address of the target memory.


Figure 25 Code from Flash main binary that is used for v[7]

Further into the call to the call_virtual_protect function, it eventually calls the VirtualProtect API to give execute permission to target memory. By reusing code from the Flash binary itself, the exploit defeats DEP.


Figure 26 Code inside call_virtual_protect




Executing shellcode

With the exploit already defeating ASLR by full memory access and defeating DEP by reusing Flash binary code that can change permission on a designated memory location, the rest is relatively easy. The exploit builds the shellcode first (Figure 27), and modifies v[7] to a shellcode address. The v[7] is the function pointer to a cancel method. (Figure 28)


Figure 27 Build shellcode



Figure 28 Replacing the function pointer for the cancel method inside the fake FileReference object and running it


When additional cancel methods are called, the fake function table looks like Figure 29. The address pointed to by v[7] has already been made executable by previous calls to the cancel method that calls VirtualProtect API. (Figure 23)


Figure 29 Replaced v[7], function pointer for cancel



CVE-2014-0515 is a really interesting vulnerability with the Pixel Bender engine. The metadata parser is expecting fixed-size data, but if you supply larger data intentionally, it can overflow and overwrite the operand byte code of adjacent instructions. This memory corruption leads to further memory corruption involving byte code interpretation. Even if you can only control where to write the data, not what to write, you can still use Vector length corruption to achieve further access to lower level memory. With full access to process memory, ASLR and DEP can be easily defeated. Everything looks very similar to the CVE-2014-1776 exploit we talked about previously. But, the style of the exploit itself is quite different. The way the heap spray is laid out is quite different and the way how it finds gadget and function addresses is different. We might well see similar or variant styles of this exploit in the future.



0 Kudos
About the Author


Twitter: @ohjeongwook .

Steve Sims
on ‎05-31-2014 04:25 PM

Awesome write-up. Thanks for posting. It's a really neat bug and cleverly exploited.

on ‎12-19-2014 01:30 AM



I'm very impressed your aticle.


Currently, I study CVE-2014-0515. but my swf sample isn' matach yout swf sample version.


so I meet with a diffculty,


Could you give me a sample?


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