SpiderLabs investigates a number of suspicious binary files on a daily basis. A week ago we came across a PDF file which had two different vulnerabilities, a remote-code-execution vulnerability in Adobe Reader and a new escalation-of-privileges vulnerability in Windows Kernel.
Just recently we confirmed that the new escalation-of-privileges zero day (CVE-2013-5065) has been delivered in the wild using CVE-2013-3346 as a container. Our goal in this blog post is to raise the public awareness by describing the technical details behind this recent kernel zero-day. We've tested the zero day on Windows XP and Server 2003 only.
What would a PDF file have to do with a kernel vulnerability?
These days, Adobe Reader is more safe to use because Adobe did a good job implementing an additional layer of security – the sandbox.
Any code in the recent versions of Adobe Reader renderer will be sandboxed and enforced by a policy. This means that even after a successful exploitation of the renderer, the injected code will be contained and the attacker's shellcode will run under limited privileges (e.g. one can't launch a new process using the shellcode). More details about the Adobe Reader Sandbox can be found here.
At this time, the sandbox can be bypassed in one of the following ways:
- Broker Vulnerability(Adobe Reader)
- Kernel Vulnerability
The investigated sample exploited CVE-2013-3346(Adobe Reader ToolButton Remote Code Execution Vulnerability) using heapspray and ROP, in order to gain code execution in the context of Adobe Reader. The shellcode proceeds to exploit the kernel zero-day in order to bypass the sandbox and deliver the final payload (Trojan/virus executable).
First let's outline the stages of this attack:
- Obtain enough information about the context to resolve library functions' addresses (ReadFile,CreateFile,WinExec etc.) using the Process Environment Block.
- Allocate Memory at address 0x0 (ZwAllocateVirtualMemory), to be executed by the kernel (will be explained in more detail below).
- Pad the allocated page(at 0x0) with 0x0EF5 NOPs.
- Copy a small portion of the shellcode (at offset 0x303-0x40E) to the 0x00000EF5 address. These copied opcodes will later be used by privileged kernel code to elevate permissions and bypass the sandbox.
- Get a handle of the vulnerable NDProxy driver (using CreateFile).
- Trigger the zero day (CVE-2013-5065) by sending arbitrary TAPI control function.
(After this stage, the sandbox is bypassed and the Adobe renderer process is running as SYSTEM) – detailed under "The Kernel Vulnerability Ringing 0 Using TAPI"
Back To User Mode:
Decode the <<obj 4 0>> in the PDF file to an executed binary, and then save it to the %temp% folder.
- Execute the saved binary (Trojan/Virus).
The Kernel Vulnerability - CVE-2013-5065 - Ringing 0 Using TAPI:
What is TAPI? From the Microsoft Developer Network, "[Telephony Application Programming Interface (TAPI)] is a set of APIs that simplify and abstract the details of making telephony connections between two or more devices."
NDProxy is a system-provided driver, which allows us to perform various network operations with devices capable of Telephony operations. Essentially NDProxy is the user interface for Telephone operations. As such, it is possible to invoke the DeviceIoControl WinAPI with a handle to NDProxy in order to perform TAPI operations.
When invoking the DeviceIoControl API with a handle to NDProxy driver, the kernel will trigger the NDProxy!PxIODispatch function inside the driver. As the name suggests, the function is responsible for Dispatching I/O instructions (PxTapiLineBusy, PxTapiDial, PxTapiAnswer etc.).
The DeviceIoControl Function:
BOOL WINAPI DeviceIoControl(
_In_ HANDLE hDevice,
_In_ DWORD dwIoControlCode,
_In_opt_ LPVOID lpInBuffer,
_In_ DWORD nInBufferSize,
_Out_opt_ LPVOID lpOutBuffer,
_In_ DWORD nOutBufferSize,
_Out_opt_ LPDWORD lpBytesReturned,
_Inout_opt_ LPOVERLAPPED lpOverlapped
First, In order to get to the vulnerable flow, we'll have to instruct the kernel to perform a TAPI operation. This can be achieved by invoking DeviceIoControl API with the value of 0x8fff23c8 as its dwIoControlCode:
In order to determine which TAPI operation to execute, the function PxIODispatch will rely on the lpInBuffer structure – supplied by DeviceIoControl. Considering this fact we have to build a buffer structure with the value of 0x7030125 in its 0x14 offset.
Let's take a look at the PxIODispatch instructions that will determine which PxTapi function to execute:
mov eax, [esi+14h] ; 0x7030125 (lpBuffer+0x14)
sub eax, 7030101h ;(0x7030125-0x7030101) =24 =eax
f78400b0 8d0440 lea eax,[eax+eax*2] ; 24+24*2 = 0x6C
f78400b3 c1e002 shl eax,2
kd> r eax
mov dword ptr [ebp+LockState.LockState], eax ;save result for later use
Therefore: (3*(0x7030125-0x7030101))*4 = 0x1B0;
This result is then used as an index to a static function table in order to decide which PxTapi function will be executed.
A snippet from that table(starts at 0x18188):
The address at [functionTable+0x1B0] is out of the table boundaries and therefore points to a pointer with the value of 0x38:
Eventually the code tries to execute a function from the table by the given index (0x1b0 – the math result from above):
The above call will resolve the pointer at 0x18338(table+0x1B0) which points to 0x38(instead of a valid pxTapi function), then execute the code at 0x00000038.
BAM - Blue Screen
Here you can see the stack trace of the crash reproduced in our lab environment:
Back to Adobe Reader Vulnerability - what is being executed by the kernel?
Remember what the PDF shellcode already did? As described in "The Shellcode" paragraph above, the shellcode already allocated an address space and filled the memory at 0x38 with NOPs sled followed by some opcodes.
These opcodes are specially designed to run in ring 0 and the execution of these bytes will utilize the high privileges of the kernel context to elevate AcroRd32.exe (renderer) privileges using the following stages:
- Invoke nt!PsLookupProcessByProcessId call to get the EPROCESS structure of sandboxed AcroRd32.exe (renderer) process.
- Invoke nt!PsLookupProcessByProcessId call again to get the EPROCESS structure of "SYSTEM" process (PID:4).
- Replace "AcroRd32.exe" EPROCESS Token with a copy of "SYSTEM" Process Token.
- Clear the "AcroRd32.exe" EPROCESS Job field.
At this point the sandbox has been bypassed and the execution goes back to the user-mode context (AcroRd32.exe) to execute the embedded (obj4) Trojan/virus.
Here's a C++ snippet, for those of you who want to see for yourself:
Trustwave's Secure Web Gateway blocks this attack out-of-the-box using its generic protection engine and did so without any additional updates.
Microsoft offers a solution for this issue here: