The Latest Flash UAF Vulnerabilities in Exploit Kits


Recently, several popular exploit kits, including Angler, Flash EK, SweetOrange, Fiesta andNeutrino[1], have included several use-after-free (UAF) vulnerabilities in Adobe Flash to exploit victims’ browsers. Previously, these exploit kits typically used out-of-bounds access (OBA) vulnerabilities in Adobe Flash, as these types of vulnerabilities can be exploited universally and stably [2], and require less effort to exploit compared to UAF vulnerabilities. In order to detect these newly added UAF vulnerabilities, we analyzed the code found in the exploit kits to determine which vulnerabilities are present and how they are exploited.

Obfuscation in exploit kits

To determine the vulnerabilities within each exploit kit, we first had to overcoming the various obfuscation methods present in the JavaScript. Each exploit kit employs a different set of obfuscation methods, as seen in Figures 1, 2 and 3; however, the main JavaScript obfuscation methods seen in these kits are JavaScript function hooks, variable substitution and no operation (NOP) insertion. The most common obfuscation method seen in these exploits scripts is variable substitution, in which the JavaScript will use regex, math, concat, split, replace and other functions to manipulate and construct values that the script assigns to variables. The analysis of the exploit kits and details on the obfuscation methods used by specific exploit kits are beyond the scope of this report.


Figure 1. Angler’s JavaScript Obfuscation


Figure 2. SweetOrange’s JavaScript Obfuscation


Figure 3. Fiesta’s JavaScript Obfuscation

The exploit kits also use obfuscation methods within the ActionScript code inside the Flash SWF files loaded by the malicious JavaScript. Similar to the exploit kit’s JavaScript, the obfuscation methods found in the ActionScript also include variable substitution and NOP insertion, which requires deobfuscation and increases the effort required to decompile and analyze the ActionScript. Further obfuscation methods used in the SWF files, which is almost universal amongst the different exploit kits, involves packing the SWF in several layers by using the “Loader::loadbytes()” function. As shown in the Figures 4 and 5, the layers of obfuscation just add complexity and increase the level effort required to analyze the vulnerability, as the most internal layer is always the exploit layer.


Figure 4. Angler’s SWF Obfuscation, Layer 1


Figure 5. Angler’s SWF Obfuscation, Layer 2

Vulnerability analysis

Once the JavaScript and ActionScript are deobfuscated, we can locate the specific vulnerabilities and determine how they are exploited. The use-after-free vulnerabilities involved in these popular exploit kits are CVE-2015-0311, CVE-2015-0313 and CVE-2015-0359, which we discuss elsewhere in this report. We found that these three CVEs discuss vulnerabilities in the same ApplicationDomain class. Every ActionScript class has an application domain, usually held by LoaderContext, to define its security context, especially when loading an external SWF by using Loader::load() or Loader::loadbytes(). Figure 6 shows the ApplicationDomain definition in Adobe’s documentation.


Figure 6. Adobe’s definition of ApplicationDomain

The ApplicationDomain class has a property, domainMemory, which can be set to a ByteArray Object. The domainMemory ByteArray Object can be shared by other threads or used by other methods or classes. The use-after-free vulnerability arises because the ApplicationDomain relies on notifications to synchronize objects, whereas the other thread or class/method does not send a message when they free the ByteArray. The ByteArray that was free is still referenced by the ApplicationDomain because it was not notified that the ByteArray was freed. For instance, ByteArray::compress and ByteArray::decompress do not notify the ApplicationDomain when they free a ByteArray due to an IOError, or when a worker thread does not notify the main thread when it frees a ByteArray, which both cause the use-after-free situation.

During our analysis, we found that the Angler exploit kit not only forgot to obfuscate its exploit layer within the ActionScript found within the malicious SWF file, but also used helpful variable and function names that made it very easy to understand. Due to its straightforward nature, we will use Angler’s SWF as an example to show a step-by-step process to describe how it exploits the CVE-2015-0313 vulnerability.

In the first stage, the ActionScript performs heap layout work, sets a byteArray buffer named “attacking_buffer” to “ApplicationDomain.currentDomain.domainMemory”, and sends a message to trigger the worker thread. Figure 7 shows the ActionScript within Angler’s malicious SWF file.

Figure 7. Angler’s ActionScript that Assigns a Buffer to domainMemory to Begin the Exploitation Process

The following displays the memory map for the pertinent objects after the first stage, specifically showing domainMemory and ByteArray having a pointer (yellow) to the ByteArrayData buffer (actually the ByteArrayData was set to domainMemory):

05591c60 10bb6558 80025f01 05555f98 03e831f0
05591c70 03ea5040 039f3080 03b672b8 03b661e8
+0x00: vtable of ApplicationDomain
+0x10: pointer to domainMemory

03ea5040 10c99fc8 03b4c190 0577f6d0 039f3080
03ea5050 03ea6020 05069000 00002000 03a36ea0
03ea5060 00000003 03ea5040 039f1070 039f1040
03ea5070 00000000 00000000
+0x00: vtable of domainMemory
+0x14: pointer to ByteArrayData

03a4f578 10c890a8 00000002 05069000 00002000
03a4f588 00002000 00000000
0x00: vtable of ByteArray
0x08: pointer to ByteArrayData

05069000 33333333 33333333 33333333 33333333
05069010 33333333 33333333 33333333 33333333
05069020 33333333 33333333 33333333 33333333
05069030 33333333 33333333 33333333 33333333
05069040 33333333 33333333 33333333 33333333
05069050 33333333 33333333 33333333 33333333

In the second stage, the worker thread receives the message and clears the “attacking_buffer” ByteArray assigned to “ApplicationDomain.currentDomain.domainMemory” in the first phase. However, the script does not notify the ApplicationDomain that the “attacking_buffer” was cleared, which causes “ApplicationDomain.currentDomain.domainMemory” to retain a pointer to the ByteArrayData. The lack of notification in the event of clearing the ByteArray causes the UAF vulnerability. Figure 8 shows the ActionScript within Angler’s malicious SWF file that clears the buffer without notifying the ApplicationDomain.

 Figure 8. Angler’s ActionScript that Clears the Buffer Without Notifying the ApplicationDomain

The following shows a memory map of the objects after the second stage, showing the ByteArray being cleared and the buffer of ByteArrayData being freed, but the domainMemory retaining the pointer (yellow) to the ByteArrayData buffer:

03ea5040 10c99fc8 03b4c190 0577f6d0 039f3080
03ea5050 03ea6020 05069000 00002000 03a36ea0
03ea5060 00000003 03ea5040 039f1070 039f1040
03ea5070 00000000 00000000
+0x00: vtable of domainMemory
+0x14: pointer to ByteArrayData

03a4f578 10c890a8 00000001 00000000 00000000
03a4f588 00000000 00000000

05069000 00000000 00000000 00000000 00000000

Exploit Analysis

After triggering the UAF vulnerability, the third stage begins the exploitation process. This is a rather special and unique UAF vulnerability, as the ByteArray object can be any size, which allows exploiters to create and free an arbitrary sized heap block, fill it with an arbitrary sized object (the simplest method is filling the freed heap block with the vector object), and modify the arbitrary offset of this freed buffer to an arbitrary value. he freed buffer is still considered a ByteArray buffer of domainMemory, allowing the exploiter to read and write directly to the ByteArray buffer using alchemy opcodes. For example, the alchemy opcodes ‘op_li32’ and ‘op_si32’ can read and write 32-bits memory of the ByteArray buffer of domainMemory.

The exploitation process continues by taking over the freed ByteArrayData heap block and replacing it with a vector of the same size. Angler’s exploit code, seen in Figure 9, takes over the ByteArrayData buffer in the function “make_filling_by_uints” and changes the vector length to a very large size by using the alchemy opcodes ‘op_si32’ in the function “magic_write_uint”.

 Figure 9. Angler’s Exploit Code Taking Over ByteArrayData Buffer and Changing its Size

Figure 10 is a memory map of relevant objects after the third stage. The freed ByteArrayData buffer starting at 0x05069000 (yellow) has been taken over by the VectorData buffer that starts at 0x05069020 (green) and has a size of 0x72. The memory map also shows that the length of VectorData has been set to 0x40000000 (red).

03ea5040 10c99fc8 03b4c190 0577f6d0 039f3080
03ea5050 03ea6020 05069000 00002000 03a36ea0
03ea5060 00000003 03ea5040 039f1070 039f1040
03ea5070 00000000 00000000
+0x00: vtable of domainMemory
+0x14: pointer to ByteArrayData

05661538 10c99918 00000003 0555c1f0 03a44d78
05661548 0555f150 00000000 05069020 00000000
05661558 00000000 00000000
0x00: vtable of Vector<uint>
0x18: VectorData

Overlapped ByteArrayData[freed, +0x00 begin] and VectorData[taken over, +0x20 begin]
05069000 00000000 00000000 0506a000 05066000
05069010 01f80008 00000000 00000000 10f69b44
05069020 40000000 0506bc00 feedbabe 00001590
05069030 babeface 00000000 00000000 00000000
05069040 00000000 00000000 00000000 00000000

050691e0 00000000 00000000 00000000 00000000
050691f0 bbbbbbbb bbbbbbbb bbbbbbbb bbbbbbbb
05069200 bbbbbbbb bbbbbbbb bbbbbbbb bbbbbbbb
05069210 bbbbbbbb bbbbbbbb 00000072 03b3b000
05069220 feedbabe 00001591 babeface 00000000
05069230 00000000 00000000 00000000 00000000

05069020+0x00: vector length modified to 0x40000000 by alchemy opcode of domainMemory
05069020+0x04: GC_object<***important***>
05069020+0x08: vector[0]
05069218+0x00: length of the next adjacent vector

Figure 10. Memory Map Showing the ByteArrayData Buffer Taken Over by Vector Buffer

The last stage starts by finding the vector with the size of 0x40000000 by comparing the original length to current length. Figure 11 shows a function named ‘find_unchained_vector’ within the ActionScript that locates the vector, specifically seen in red text. The ActionScript will use this vector to scan memory to find ROP chain, construct and write ROP chain and shellcode (obtained from flashvars) to the VectorData buffer, which is a fairly conventional process. The interesting part of the exploitation process involves the use of the garbage collection (GC) to control the instruction pointer (EIP) instead of the typical usage of a sound or file reference object to control EIP[2]. The exploit code uses the garbage collection (GC) to control EIP by faking a GC_object at offset 0x04 of the VectorData buffer and will overwrite it to the controlled fake_GC_object, which is carried out by a function named “take_over_32” in Figure 11. According to the memory map in Figure 10, the first element of vector is offset 0x08 (vector[0]), but the ActionScript overwrites the offset 0x04 instead, which is interesting and required additional analysis.

 Figure 11. Angler’s ActionScript Code to Find and Take Over the Vector

From within the ActionScript, we can see it specifically set vector[3fffffff] to fake_gc_object, which Flash will calculate the offset like this in the following manner:

Vector[index] -> [VectorData+index*4+8]
When index = 3fffffff
[VectorData+0x3fffffff*4+8] = [VectorData+0xfffffffc+8] = [VectorData+0x04]

Based on the calculation above, it is obvious that the ActionScript uses an integer overflow to set vector+0x04 offset. After setting the vector+0x04 to the fake_gc_object, it resets the vector length (unchained_vector.length) to release the old vector and triggers garbage collection (GC) to collect this vector. When the garbage collector collects the vector it uses the fake_gc_object, gets an unknown object from this fake_gc_object and peforms a vtable call on this unknown object.

Figure 12 shows the trace route of the garbage collector and the memory map in the last stage to show the process in which exploiters use to control the instruction pointer to execute code. This will not show the entire process of the garbage collector, instead it begins from finding the vector to be collected and ends with the vtable call on the unknown object that provides exploiters control over the EIP.

 Figure 12. Trace of Garbage Collector and Associated Memory Map

The use of the garbage collector is a novel method to control EIP, which differs from the previous techniques using sound or file reference objects. It is universal, stable and does not require other objects, as attackers can use the one vector for all the steps required to execute code, including scanning for and finding the ROP chain, overwriting the ROP chain, and control and trigger EIP. This is good news for cybercriminals, as it makes exploit development easier.


The technique of faking a garbage collection object to control EIP has never been seen before and is worth to paying attention to in future exploits. Due to certain features in Adobe Flash, specifically the ability for alchemy opcodes (such as op_li32/op_si32) to directly access memory within a ByteArray, use-after-free vulnerabilities are just as easy to exploit as out-of-bounds vulnerabilities. It appears that the authors of exploit kits agree with this, as they continue to add new Flash UAF vulnerabilities to their arsenal. As such, we can anticipate Flash vulnerabilities will continue to be exploited by exploit kits well into the future. Security researchers should not only spend time hunting and reporting more bugs to vendors, but also focus on exploit detection before html5 completely replaces flash altogether.




Got something to say?

Get updates: Unit 42

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