Adobe Flash Player 0-day Exploit Analysis (CVE-2011-0611) A step-by-step discussion of the latest Flash Player 0-day exploit Secunia Research 14/04/2011 Secunia.com 1 As mentioned in our previous blog post [1] and Secunia Advisory SA44119 [2], 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 [3] 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 00002E10 00002E20 00002E30 66 78 00 53 55 00 00 63 66 05 00 65 55 5F 43 6E 75 00 02 65 27 00 FF 20 00 0F FF 31 00 A0 FF 00 46 00 BF 00 57 00 15 BF 53 18 0B 14 0A 01 00 1A 75 00 00 27 27 44 00 00 00 11 01 00 00 08 00 01 fUfUu'..FWS.u'.. x.._.........D.. ...C............ 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 00000040 00000050 0E 12 9D 02 00 4C 04 9D 02 00 18 00 88 15 00 09 .....L.......... 00 41 00 42 00 43 00 44 00 45 00 46 00 47 00 48 .A.B.C.D.E.F.G.H 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). Secunia.com 2 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 bitwiseAnd branchIfTrue label2 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: label2: branch label7 label3: new push 191919126 dup ... multiple lines follow label7: push X_PROPERTY, UNDEF, X_PROPERTY, c:0 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" callFunction Secunia.com 3 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 callMethod push 3 subtract //String.charCodeAt(i) - 3 push 1, c:0 //String getVariable push c:3 //fromCharCode callMethod add setRegister r:3 ... push r:3 return 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 () { this.c_fun(); }; var eval(0) = new Date(1.41466385537348e-315); (eval(0)).getDay(); 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.com 4 [1] http://secunia.com/blog/208/ [2] http://secunia.com/advisories/44119/ [3] http://www.adobe.com/support/security/advisories/apsa11-02.html Secunia.com 5