About Us | Contact Us    



VUPEN Research

  VUPEN Research Team Blog

VUPEN Vulnerability Research Team (VRT) Blog

Criminals Are Getting Smarter: Analysis of the Adobe Acrobat / Reader 0-Day Exploit
Published on 2010-09-09 16:32:21 UTC by Nicolas Joly, Security Researcher @ VUPEN

Twitter LinkedIn Delicious Digg Slashdot

Hi everyone,

We would like to share some interesting details based on our in-depth analysis of the recent Adobe Acrobat/Reader 0-Day exploit (CVE-2010-2883).

Here at VUPEN, we analyze a lot of vulnerabilities and 0days and we create quite sophisticated exploits targeting various applications and operating systems. During the last few months, we have created a large number of Adobe Reader exploits and many of them defeated DEP.

So why is this particular 0day exploit so interesting? Because it bypasses DEP and ASLR by using impressive tricks and unusual methods that we have not seen often in the wild.

As some of you may know, the malicious PDF takes advantage of an unsecure "strcat()" call in "CoolType.dll", which results in a common stack overflow. The vulnerable function is reached when a PDF document embeds a font with a specific table.
.text:0803DCF9 push ebp
.text:0803DCFA sub esp, 104h
.text:0803DD00 lea ebp, [esp-4]
.text:0803DD04 mov eax, dword_8230FB8
.text:0803DD09 xor eax, ebp
.text:0803DD0B mov [ebp+108h+var_4], eax
.text:0803DD11 push 4Ch
.text:0803DD13 mov eax, offset loc_8184A54
.text:0803DD18 call __EH_prolog3_catch                       // set up an SE handler
.text:0803DD1D mov eax, [ebp+108h+arg_C]
.text:0803DD23 mov edi, [ebp+108h+arg_0]
.text:0803DD29 mov ebx, [ebp+108h+arg_4]
.text:0803DD2F mov [ebp+108h+var_130], edi
.text:0803DD32 mov [ebp+108h+var_138], eax


When a font with a SING table is found, the following instructions are reached:

.text:0803DD74 push offset aSing ; "SING"
.text:0803DD79 push edi ; int
.text:0803DD7A lea ecx, [ebp+108h+var_12C]
.text:0803DD7D call sub_8021B06
.text:0803DD9F loc_803DD9F:
.text:0803DD9F add eax, 10h
.text:0803DDA2 push eax                                          // long string following the SING table
.text:0803DDA3 lea eax, [ebp+108h+Dest]
.text:0803DDA6 push eax                                          // ~256 bytes stack buffer
.text:0803DDA7 mov [ebp+108h+Dest], 0
.text:0803DDAB call strcat                                        // insecure!


To exploit such bugs, an exploit writer usually overwrites a return address or an SE handler, but at first sight it does not seem feasible here. A stack cookie prevents the return address from being exploited and an SE handler is set when the function is entered, which gives the following stack:

|      SE     |
|     DEST  | <-- vulnerable buffer
|       ...   
|      EBP  


As we can see, if you try to overwrite the return address you get killed by the cookie. And if you try to trigger an exception while writing data off the stack, you get caught by the SE handler and then by the cookie. These solutions are clearly not interesting here.

As a solution, you can try to overwrite an argument or a variable defined in the caller. That's precisely what was done by the attacker. When trying to overwrite the stack, a first crash occurs in BIB.dll. This is because the next called function is using an overwritten argument:

.text:0803DDB0 pop ecx
.text:0803DDB1 pop ecx
.text:0803DDB2 lea eax, [ebp+108h+Dest]
.text:0803DDB5 push eax
.text:0803DDB6 mov ecx, ebx               // ebx actually points to arg_4, which is overwritten
.text:0803DDB8 call sub_8001243


And then:

.text:070013F7 lea eax, [ecx+1Ch]         // ecx = [arg_4]
.text:070013FA mov [ebp+var_8], eax
.text:070013FD mov eax, [ebp+var_8]
.text:07001400 lock dec dword ptr [eax] // first crash here


If an incorrect address is specified, an exception is first triggered at 0x07001400, and then caught by the SE handler which eventually crashes Adobe Acrobat/Reader. Wrong turn.

So a valid pointer here must be set. This basically allows the attacker to decrement an arbitrary dword in memory, which can be useful indeed (e.g. CVE-2008-4812), but even with this, it is still difficult to forge an exploit to bypass DEP and ASLR.

The salvation (for the attacker) came from sub_8016BDE, which takes two pointers to stack arguments:

.text:0803DEA9 loc_803DEA9:
.text:0803DEA9 lea eax, [ebp+108h+var_124]
.text:0803DEAC push eax
.text:0803DEAD push ebx
.text:0803DEAE push edi                     // ebx and edi point to arg_4 and arg_0
.text:0803DEAF call sub_8016BDE


This function actually calls sub_801BB1C with arg_0 which returns 0 or a pointer. If 0 is returned, the jump at 0x080172CE is taken and the function is exited. However if a pointer is returned, sub_801BB21 (which also uses arg_0 as a parameter) is called.

.text:08016C2B push edi
.text:08016C2C mov [ebp+664h+var_668], ebx
.text:08016C2F mov [ebp+664h+var_694], ebx
.text:08016C32 mov [ebp+664h+var_678], ebx
.text:08016C35 call sub_801BB1C       // return 0 or a pointer
.text:08016C3A cmp eax, ebx
.text:08016C3C pop ecx
.text:08016C3D mov [ebp+664h+var_67C], eax
.text:08016C40 jz loc_80172CE
.text:08016C46 push 1
.text:08016C48 push ebx
.text:08016C49 push ebx
.text:08016C4A lea eax, [ebp+664h+var_678]
.text:08016C4D push eax
.text:08016C4E lea eax, [ebp+664h+var_694]
.text:08016C51 push eax
.text:08016C52 push edi
.text:08016C53 push [ebp+664h+var_67C]
.text:08016C56 call sub_801BB21        // this call must be reached


Let's see what is executed by sub_801BB1C:

.text:0801BA57 mov eax, dword_823A728
.text:0801BA5C test eax, eax               // the attacker does not control this pointer
.text:0801BA5E jz short locret_801BA73
.text:0801BA60 mov ecx, [esp+arg_0] // however ecx may point to a controlled dword
.text:0801BA64 mov ecx, [ecx+4]
.text:0801BA67 loc_801BA67:
.text:0801BA67 cmp ecx, [eax+4]
.text:0801BA6A jz short locret_801BA73
.text:0801BA6C mov eax, [eax+8]
.text:0801BA6F test eax, eax
.text:0801BA71 jnz short loc_801BA67
.text:0801BA73 locret_801BA73:
.text:0801BA73 retn


Basically ecx must equal [eax+4] to make this function return something other than NULL. So which values are pointed by eax + 4?



Remember that since a strcat is exploited, null bytes cannot be used! Initially arg_0 + 4 points to 0x0000006D which means this value must not be touched and thus a limited amount of bytes should be copied on the stack. That's why the author of this exploit did not overwrite the whole stack but only a part. Finally sub_801BB21 and sub_808B116 are entered:

.text:0808B2E3 mov eax, [edi+3Ch] // edi = arg_0, but edi + 3Ch points to a stack pointer,
                                                     // itself pointing to a controlled value

.text:0808B2E6 cmp eax, ebx
.text:0808B2E8 mov [esi+2F4h], eax
.text:0808B2EE mov [esi+2F8h], ebx
.text:0808B2F4 mov [ebp+var_4], ebx
.text:0808B2F7 jnz short loc_808B300
.text:0808B2F9 loc_808B2F9:
.text:0808B2F9 xor al, al
.text:0808B2FB jmp loc_808B594
.text:0808B300 loc_808B300:
.text:0808B300 lea ecx, [ebp+var_4]
.text:0808B303 push ecx
.text:0808B304 push ebx
.text:0808B305 push 3
.text:0808B307 push eax
.text:0808B308 call dword ptr [eax] // EIP is redirected here


The story could end there, but the ROP sequence used is technically uncommon. Reader uses icucnv36.dll which does not change across versions (at least since Reader 9.2.0) and does not support ASLR. An exploit writer can then base his ROP on this DLL to target Reader versions >= 9.20 with the same malicious PDF file, and this library was used by the attacker.

While this DLL seems interesting, it does not import VirtualAlloc, VirtualProtect, HeapCreate, WriteMemory or even a LoadLibrary, which complicates exploitation. However, the attacker did find and use other functions:

4A84903C CreateFileA                // create the file iso88591
4A849038 CreateFileMappingA    // attrib RWE
4A849030 MapViewOfFile            // load this file in memory with RWE flags
4A849170 memcpy                    // copy the payload


The idea of the attacker was to spray the heap with a ROP pattern, followed by the shellcode. It first creates a file (iso88591) on disk, loads it with RWE attributes, copies the payload in memory and eventually executes the shellcode.

The exploit first sets esp to point to the spray with:

.text:4A80CB38 add ebp, 794h
.text:4A80CB3E leave
.text:4A80CB3F retn


followed by:

.text:4A82A714 pop esp             // esp = 0x08852030
.text:4A82A715 retn


0x08852030 actually points to a heap spray which consists in the same ROP address repeated, to make a stack spray:

.text:4A801064 retn

It is then followed by ROP addresses to map an executable page. Addresses are typically popped to eax and functions are called with:

.text:4A80B692 jmp dword ptr [eax]

You can also notice that dynamic arguments are written to the stack thanks to:

.text:4A80A8A6 and dword ptr [2*ebx + esp], edi
.text:4A80A8A9 jnz short loc_4A80A8AE
.text:4A80A8AE loc_4A80A8AE:
.text:4A80A8AE cmp al, 2Fh
.text:4A80A8B0 jz short loc_4A80A8AB
.text:4A80A8B2 cmp al, 41h
.text:4A80A8B4 jl short loc_4A80A8BA
.text:4A80A8C8 loc_4A80A8C8:
.text:4A80A8C8 xor al, al
.text:4A80A8CA retn


In the end, it calls memcpy and jumps to the payload, leading to arbitrary code execution despite DEP and ASLR.

It is unclear whether this vulnerability was found by fuzzing or static analysis. However, it seems clear that the one who designed the exploit has good knowledge of Acrobat and LiveCycle, Javascript and ROP and obviously knows how to use a debugger.

In fact, because of a single DLL, we have here a typical example of something able to help attackers to target, with the same exploit file, multiple versions of a vulnerable application, on multiple systems (Windows XP, Vista, 7), and despite the common security measures.

Note that this kind of insecure DLLs also exist in major Microsoft products...

Copyright VUPEN Security


VUPEN Solutions  











2004-2015 VUPEN Security