Adobe Flash Player 0-day Exploit Analysis (CVE-2011-0611)

By Secunia Research

A step-by-step discussion of the latest Flash Player 0-day exploit

As mentioned in our previous blog post and Secunia Advisory SA44119, a new Adobe Flash Player 0-day vulnerability is currently being exploited in the wild through Microsoft Word (*.doc) documents. The vulnerability is currently unpatched, though Adobe has scheduled a fix for Flash Player tomorrow, Friday April 15th and for Adobe Reader/Acrobat on June 14th.

The Word document is named: "Disentangling Industrial Policy and Competition Policy.doc" and embeds a SWF file at offset 0x2E08, the stream having a size of 0x2775 bytes.

00002E00  66 55 66 55 75 27 00 00 46 57 53 0A 75 27 00 00 fUfUu'..FWS.u'..
00002E10 78 00 05 5F 00 00 0F A0 00 00 18 01 00 44 11 08 x.._.........D..
00002E20 00 00 00 43 02 FF FF FF BF 15 0B 00 00 00 01 00 ...C............
00002E30 53 63 65 6E 65 20 31 00 00 BF 14 1A 27 00 00 01 Scene 1.....'...

The embedded SWF loads a secondary SWF file at runtime through a call to flash.display.Loader.loadBytes() from the "t" property. It is this secondary SWF that actually triggers the vulnerability, but it is heavily obfuscated and, therefore, not straight-forward to analyse as it manages to confuse ActionScript disassemblers, some crashing while others stop providing disassembly prematurely.

The first apparently intentional alteration of the file is the incorrect declaration of the size of a group of included constants. Namely, the size value of 0x15 included at offset 0x3D in the SWF does not correspond to the actual size of the constants (0x14), causing some disassemblers to interpret following code from an incorrect offset.

00000030  0E 12 9D 02 00 4C 04 9D 02 00 18 00 88 15 00 09 .....L..........
00000040 00 41 00 42 00 43 00 44 00 45 00 46 00 47 00 48 .A.B.C.D.E.F.G.H
00000050 00 49 00 A1 8E 11 00 64 65 66 61 75 6C 74 00 01 .I.....default..

This can be fixed by adding one character to the last constant.

00000050  00 49 49 00 8E 11 00 64 65 66 61 75 6C 74 00 01 .II....default..

Disassemblers still refuse to present proper disassembly due to the incorrect structure of the included DOACTION tag (DOACTION tags contain ActionScript bytecode in AVM2). The size of the DOACTION tag is declared as 0x05A7 inside the SWF, but the last included tags are incorrectly formed, causing overly large read attempts. This can be fixed by setting all bytes starting at offset 0x5B2 to zero (interpreted as end action tags).

It is now possible to extract the disassembly, but other problems are encountered: Several unnecessary instructions making the code difficult to read are included, but can be eliminated.

An example is the code block:

push 1212792920, -1212792921
branchIfTrue label2

This can eliminated completely since label2 is reached in all cases. Many other cases involving unnecessary stack manipulations can also be eliminated in the process.

The SWF is further obfuscated through the use of several jumps back and forth inside the code.

An example of this is:

branch label7
push 191919126
... multiple lines follow
branch label3

This can be simplified by moving label7 before label3 and eliminating both "branch" instructions.

After obtaining a better arranged code stream, the next step is to decode two important string constants included in an encoded form. These strings are included as: "VkduhgRemhfw1surwrw|sh" and "Gdwh1surwrw|sh". By studying the disassembly it can be observed that the "VkduhgRemhfw1surwrw|sh" constant is passed in a call to an internally declared "default" function prior to further usage.

constants 'String', 'length', 'charCodeAt', 'fromCharCode', 'charAt', 'case',
'TextFormat', 'size', 'c_fun',
'VkduhgRemhfw1surwrw|sh', 'default',...
push c:8, c:9, 1, c:10 //c:9 is "VkduhgRemhfw1surwrw|sh" and c:10 is "default"

The "default" function transforms an input string by subtracting 3 from each of its characters.

push r:3, r:1, 1, r:2, c:2 //String.charCodeAt
push 3
subtract//String.charCodeAt(i) - 3
push 1, c:0 //String
push c:3 //fromCharCode
setRegister r:3
push r:3

After applying the transformation to the encoded constants, the "SharedObject.prototype" and "Date.prototype" strings are obtained. Further simplification of the code is then possible by eliminating the encoding function and various other instructions.

All in all, more than 250 lines of assembly can be eliminated in the process, resulting in the following ActionScript code when decompiled:

Date.prototype.c_fun = SharedObject.prototype.getSize;
Date.prototype.getDay = function () {

var eval(0) = new Date(1.41466385537348e-315);

Further analysis of the vulnerability caused by this code shows that it's another object type confusion vulnerability occurring in SharedObject.prototype.getSize() when a Date class is extended by adding a custom function obtained via SharedObject.prototype.getSize. The Date object is initialised with the 1.41466385537348e-315 value, which transforms to 0x11111110 when saved in memory. 0x11111110 is an address suitable for heap spraying.

When the custom Date.c_fun() function is called, SharedObject.prototype.getSize() is reached and incorrectly interprets the passed Date object as having a SharedObject type, attempting to use 0x11111110 as a pointer to a virtual function table.

In conclusion, the vulnerability is proved to be obfuscated to a large degree and is also technically interesting in nature. The SWF requires no manipulation of the ActionScript bytecode after compilation from its source.

Secunia Research