[This blog was primarily written by Xiaoning Li of Intel Labs, with assistance from Peter Szor of McAfee Labs.]
In February 2013, the Adobe Product Security Incident Response Team (PSIRT) released security advisory APSA13-02. In that report they listed two vulnerabilities (CVE-2013-0640 and CVE-2013-0641) that were widely exploited. At Intel Labs and McAfee Labs we ran some further analysis of these exploits and want to share some of the interesting details we discovered.
Based on information from the PSIRT, both vulnerabilities will impact all versions of Adobe Reader from 9.x to 11.x. (Some Acrobat versions are also vulnerable.) We verified this claim and found the sample affected all of them.
Attack Path
The exploit is spread by a malicious PDF file. When Reader opens the PDF file, it will trigger the vulnerability and start the exploit. This PDF file delivers a very complex attack, bypassing the current Adobe sandbox mechanism to launch the malware.
This flow shows the basic steps for the attack path:
The files D.T and L2P.T are DLLs in a sandboxed temp path, as in the following:
A new PDF is created in the normal temp path:
The new PDF, Visaform Turkey, will appear to hide the exploitation. The exploit uses a lot of memory in the background.
First Exploit
The PDF’s first exploit uses a heap overflow to overwrite a virtual function pointer, and also uses a memory information leak to bypass the address space layout randomization (ASLR) protection in Windows. Return-oriented programming is used to bypass data execution prevention (DEP).
Let’s sidetrack for a moment and look at two definitions: Return-oriented programming (ROP) is an exploit technique in which an attacker controls the call stack to indirectly execute arbitrary intended or unintended code to deliver an attack, thereby bypassing security features such as DEP. Stack pivoting is a common technique used by ROP-based exploits. Pointing the stack pointer to an attacker-owned buffer, such as the heap, will provide more flexibility for the attacker to carry out a complex ROP exploit.
Here’s how the exploit works from the first trigger point. The vulnerability is in AcroForm.api. After the exploit prepares customized stack data on the heap, the data triggers the exploit via following instructions in AcroForm.api.
With a modified virtual function pointer, the instruction calls into a special ROP gadget, which will start pivoting.
The address for the first gadget is 0x209b9f50. Here’s the original code:
But if we decode from 0x209b9f50, the code piece looks like what follows. This is the ROP gadget for stack pivoting:
Now the stack points to a fake stack in the heap. The code log in a debugger at runtime looks like this:
Once the customized stack works, it will start more ROP gadgets. When the next Ret instruction is called, the stack looks like this:
What’s the instruction for 0x6acc1049? It is offset 0×1049 from AcroForm.api because 0x6acc00 is the base address for the target module. Here is the unintended ROP gadget again:
The decoded ROP gadget is just a Ret instruction:
It will repeat from stack 0x11849a34 to stack 0x1184beb4, a whopping 9,344 (0×2480) times!
Let’s see what the stack content is now:
The next gadget will move the esp register to esi. It will control the stack itself.
The gadget still includes lots of return addresses with repeated patterns, such as these:
With related code pieces:
So the logic will write target memory with values in the ecx register. The same pattern will repeat many times to modify 0x6b55e001, which is the beginning of the data section of AcroForm.api.
The data from 0x6b55e001 to 0x6b55e04e is modified and writes several API/DLL names into the area of 0x6b55e001:
- GetTempPathA
- Fwrite
- Wb
- CryptStringToBinaryA
- Ntdll
- RtlDecompressBuffer
- Wcsstr
These strings are later used as parameters, during ROP-based API calls. After writing these strings into the data section, the ROP code continues with the following gadgets:
We can list the first piece of an ROP gadget step by step. The following code moves [esp] to ecx:
6b218551
1184c074 cccc0240 6b022c74 6b19567b 6ad6ed72
1184c084 6b19567b 6b237664
6b218551 58 pop eax
6b218552 c3 ret
6b022c74 0fb7c0 movzx eax,ax
6b022c77 c3 ret
6b19567b 97 xchg eax,edi
6b19567c c3 ret
6ad6ed72 01f7 add edi,esi
6ad6ed74 c3 ret
6b19567b 97 xchg eax,edi
6b19567c c3 ret
6b237664 91 xchg eax,ecx
6b237665 c3 ret
The following code moves the pointer to eax, and then writes [eax] with the previous value in ecx:
6b218551 cccc023c
1184c094 6b022c74 6b19567b 6ad6ed72 6b1d943b
1184c0a4 6b16d51a
6b218551 58 pop eax
6b218552 c3 ret
6b022c74 0fb7c0 movzx eax,ax
6b022c77 c3 ret
6b19567b 97 xchg eax,edi
6b19567c c3 ret
6ad6ed72 01f7 add edi,esi
6ad6ed74 c3 ret
6b1d943b 57 push edi
6b1d943c 58 pop eax
6b1d943d c3 ret
6b16d51a 8908 mov dword ptr [eax],ecx
6b16d51c c3 ret
The following code gets the LoadLibraryA() API pointer from the import table:
1184c0a4 6b218551 6b32b234 6b1d92ac
6b218551 58 pop eax
6b218552 c3 ret
6b1d92ac ff10 call dword ptr [eax]
6b1d92ae c3 ret
At this point, the stack keeps the parameter for LoadLibraryA(). This is actually a string for MSVCR100.dll in the “idata” section.
Once the MSVCR100.dll handle is available via LoadLibraryA(), the following code writes the handle to the target address in the heap (actually the fake stack), which is used to call GetProcAddress() as the first parameter. The address is 0x1184c0e4.
1184c0b4 6b237664 6b218551 cccc022c
1184c0c4 6b022c74 6b19567b 6ad6ed72 6b1d943b
1184c0d4 6b16d51a
6b237664 91 xchg eax,ecx
6b237665 c3 ret
6b218551 58 pop eax
6b218552 c3 ret
6b022c74 0fb7c0 movzx eax,ax
6b022c77 c3 ret
6b19567b 97 xchg eax,edi
6b19567c c3 ret
6ad6ed72 01f7 add edi,esi
6ad6ed74 c3 ret
6b1d943b 57 push edi
6b1d943c 58 pop eax
6b1d943d c3 ret
6b16d51a 8908 mov dword ptr [eax],ecx
6b16d51c c3 ret
Next the process calls the following gadgets to get function pointers for the wcsstr function. The first parameter is a DLL handle received from previous gadgets.
1184c0d4 6b218551 6b32b1ec 6b1d92ac
6b218551 58 pop eax
6b218552 c3 ret
6b1d92ac ff10 call dword ptr [eax]
6b1d92ae c3 ret
Now it’s time to call the function with the jmp eax gadget.
1184c0e4 6acce598
6acce598 ffe0 jmp eax {MSVCR100!wcsstr (6c5f20f1)}
Here the code searches for the string “MODULE” from the heap or the fake stack. There is a long string in the heap following the “MODULE” signature. This is the encoded and compressed DLL D.T. With more gadgets, the code calls CryptStringToBinaryA() to convert this string to binary, and then calls RtlDecompressBuffer() to decompress the binary to the real D.T binary code in memory.
Similar ROP gadgets get ntdll.dll and related API addresses, for example, RtlDecompressBuffer() and CryptStringToBinaryA(). Finally, the ROP gadget calls GetTempPathA() to get the current temp path, the sandboxed path. It will create D.T under this path and call LoadLibraryA() to run the D.T. module.
D.T creates two threads. One shows error messages. The second creates and loads the DLL L2P.T, which exploits the second vulnerability to load L2P.T into a nonsandboxed acrord32 process. Finally this process terminates.
Second Exploit
The second exploit triggers the vulnerability at acrord32.exe:
Due to a heap overflow, the eax register calls to the stack-pivoting ROP gadget.
A few more ROP gadgets after stack pivoting load L2P.T in the same process. L2P.T creates another DLL, langbar.dll, which downloads the rest of the malware.
No Shell
After we reviewed all of the exploit code and corresponding ROP, we found that this exploit does not use any traditional shellcode. All API calls use the fake stack from the stack pivoting.
Mitigation
Stack pivoting is a very common technique to allow an exploit to run powerful gadgets with a fake stack. For this kind of complex case, it’s very hard to create a customized stack within the real stack instead of within a fake stack. Once an exploit can do stack pivoting, it can bypass different defense mechanisms. Evolving security solutions need to address this attack pattern. Stack pivoting creates a very complex ROP attack and is a good example of how exploitation techniques continue to evolve. This successful exploit bypasses both Adobe client security features and basic Windows DEP and ASLR defenses.
We thank our colleagues Haifei Li, Bing Sun, Xiaobo Chen, and Chong Xu for their help with this analysis.