It is almost one year ago I found a heap overflow in Foxit Reader. I published a PoC exploit on exploit-db. Yesterday I decided to write a little explanation about the vulnerability and how I exploited it.
Foxit Reader offers the possibility to convert several file formats to PDF format. PNG is one of those file formats. A PNG file consists of several data block called chunks. One of these chunks is a textual chunk (tEXt). This chunk type is used for meta data. You can use to set an author, a title or a discription for the PNG. This chunk type consists of three parts:
- Keyword: 1-79 bytes (character string)
- Null separator: 1 byte
- Text: n bytes (character string)
The keyword part indicates which kind of data contains the text part. Foxit Reader uses a plugin to do the conversion. The code is located in ConvertToPdf_x86.dll. During the conversion Foxit Reader also parses the tEXt chunks of a PNG file to get timestamp. If a tIME chunk exists in the file, the tEXt chunks isn’t parsed. The function sub_101ab900 checks for the “Title” and the “Author” keyword. In that function is checked which keyword is used in the current chunk. To reach that several keywords are checked and for each keyword the function sub_10314b20 is called which is similar to strncmp. This function returns 0 if the strings are equal or 0 is given as number of character to compare. If there is not a keyword set in the chunk, an empty string and 0 for number of bytes are given to the strncmp function. When the function returns 0 the caller function interprets this that the strings are equal. Due to the “Time” keyword is the first checked keyword, the relevant code for “Time” is called. The function sub_10314ac0 is similar to strcpy and copies the keyword to a memory space in the heap. Since no keyword is in this chunk the description is used as source. If the size of the description is at least 44 bytes, it is possible to overwrite a pointer to an object. The Application crashs, because of a call of a function of an object to which the overwritten this pointer would points to.
ModLoad: 66fd0000 67548000 C:\Program Files\Foxit Software\Foxit Reader\Plugins\Creator\x86\ConvertToPDF_x86.dll (8a0.918): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=00000000 ebx=0656c4d0 ecx=41414141 edx=00000000 esi=0656c660 edi=0656a8a8 eip=66fe5309 esp=0024a140 ebp=0024a154 iopl=0 nv up ei ng nz ac po cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010293 *** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Foxit Software\Foxit Reader\Plugins\Creator\x86\ConvertToPDF_x86.dll - ConvertToPDF_x86!CreateFXPDFConvertor+0xb0e9: 66fe5309 8b01 mov eax,dword ptr [ecx] ds:0023:41414141=???????? 0:000> u ConvertToPDF_x86!CreateFXPDFConvertor+0xb0e9: 66fe5309 8b01 mov eax,dword ptr [ecx] 66fe530b 8b4004 mov eax,dword ptr [eax+4] 66fe530e 57 push edi 66fe530f 8d55f4 lea edx,[ebp-0Ch] 66fe5312 52 push edx 66fe5313 681a010000 push 11Ah 66fe5318 ffd0 call eax
The challange in the exploit was to reach my code. It was possible to overwrite a pointer to an object, also known as this pointer. I need to find a possiblity to overwrite the this pointer that it points to a vtable pointer which points to an address which points to my code. Since Foxit Reader makes use of ASLR this wasn't that easy.
The this pointer points to an address on the heap near my code. So I decided to use the partial overwrite approach to overwrite just the last two bytes of the this pointer. Due to the partial overwrite I had just 40 bytes to place my ropchain and my shellcode. Therefor I decided to add another tEXt chunk to the PNG file. I wrote 4000 'A' in that chunk to have enough space and I had to change the this pointer again. Now the pointer pointed to memory which was controlled by me.
The first 4 bytes in an object are interpreted as vtable pointer. This is a pointer which points to a virtual function table which contains pointer to virtual functions. The next step was to find an address which I can place there. So I needed an address which points to an address which points to code. I could not make use of heap spraying to get fixed addresses, therefor I wrote a little script for Immunity Debugger. This script looked of exactly that what I need - a pointer to a pointer to code. All valid pointer were written to a file. Because of ASLR I had to do that several times and compare the created file to find stable addresses. I found some addresses, but only one was usable:
0x10009b40 -> another address -> the following gadget: MOV EDX,DWORD PTR SS:[ESP+2C]; MOV EAX,DWORD PTR SS:[ESP+28]; PUSH EDX; MOV EDX,DWORD PTR SS:[ESP+24]; PUSH EAX; PUSH ESI; PUSH EDX; PUSH EDI; CALL DWORD PTR DS:[ECX+14]
Now it was possible for me to look for stack pivot gadgets. I had to use some JOP to get ESP to the heap. After that it I could execute a ropchain to make the heap executable to execute any shellcode. For more details about the ropchain look at the exploit. For ropchain building I could use jrsysCrypto.dll which was provided by Foxit Reader and didn’t make use of ASLR.