Foxit Reader 3.0

Today we will go for a lightweight review on a recently discovered vulnerability in Foxit Reader 3.0. As exposed by Core Security version 3.0 in builds prior to or equal to 1301 contained multiple vulnerabilities. Today I will focus on the stack based buffer overflow that happens when a file opening action happens inside a pdf object. At this point I suggest to take a quick look at the description that Didier Stevens gave in his blog about pdf's file structure, It'll come in handy when building & understanding malformed pdf files. Anyway, I'll provide a quick walkthrough here: Basically PDF files contain a small header displaying the pdf file version being used, for example: %PDF-1.1 From then on, you can have a set of objects organized in a tree structure, each object being a extension sub-tree of another object: the only exception of this rule is the root object. Therefore, and as stated in Didier's post, the logical and physical setup of the objects are independent. At the end we add two special sections called xref and trailer where the first serves as sort of an index to the different objects in the document and the second marks the end-of-file and points to the root object inside the file. Our intend when it comes to exploiting the vulnerability is to create a object inside the file that will try to open a file from the filesystem provided a filename. As part of our review, we will make use of this exploit by SkD. This exploit will build a bogus pdf file that we can feed to Foxit Reader and analyze from then on. As stated in Core Security's advisory the fun begins when Foxit Reader tries to determine if the filename provided is a relative path or absolute path, the code in question looks like this:
.text:00403019                 push    eax             ; pszPath
.text:0040301A                 call    ds:PathIsRelativeA
.text:00403020                 test    eax, eax
.text:00403022                 jz      loc_4030C8      ; We take this jump
.text:00403028                 mov     ecx, [esp+968h+arg_C]

.... < jump over this code > ....

.text:004030C8                 mov     edi, [esp+968h+var_948]
.text:004030CC                 cmp     edi, ebp
.text:004030CE                 jz      short loc_4030D5
.text:004030D0                 add     edi, 0Ch
.text:004030D3                 jmp     short loc_4030DA
.text:004030D5 ; ---------------------------------------------------------------------------
.text:004030D5
.text:004030D5 loc_4030D5:                             ; CODE XREF: sub_402690+A3Ej
.text:004030D5                 mov     edi, offset byte_A4F270
.text:004030DA
.text:004030DA loc_4030DA:                             ; CODE XREF: sub_402690+A43j
.text:004030DA                 or      ecx, 0FFFFFFFFh
.text:004030DD                 xor     eax, eax
.text:004030DF                 repne scasb
.text:004030E1                 not     ecx
.text:004030E3                 sub     edi, ecx
.text:004030E5                 lea     edx, [esp+968h+FindFileData]
.text:004030EC                 mov     eax, ecx
.text:004030EE                 mov     esi, edi
.text:004030F0                 mov     edi, edx
.text:004030F2                 shr     ecx, 2
.text:004030F5                 rep movsd               ; Trigger overflow
.text:004030F7                 mov     ecx, eax
.text:004030F9                 and     ecx, 3If we place a breakpoint where the application checks wether the path is relative or absolute, we get a nice view of the bug in question. In this particular case the path provided is absolute, therefore the check will return 0 in eax and execution will jump to
0x004030C8. In this snippet the program places the file path in edi and proceeds to calculate the length of the filename to later store it in ecx. Now all that's left is to load the source (esi) and destination (edi) register and perform a rep movs operation which will copy our filename from the pointer in esi to edi as long as ecx is not zero. In this particular case, the exploitation path is not the one we used to see in the previous reviews, this time we won't go for a stack return overwrite. Another possible exploitation vector is to abuse the fact that every thread in windows saves in the stack a linked list of exception handlers to catch any exception. This structure also known as Structured Exception Handler (SEH) is referenced by the program everytime the program triggers a exception and each stack frame contains a handler and a pointer to another exception handler in another frame. By doing this, each function that raised and exception looks in his own stack frame SEH and if the exception cannot be handled, is raised again to the next SEH in the call stack. So how can we make profit out of the SEH? Well, as I already said, each SEH record is placed in the stack frame prior to the ret value. If we overwrite one of this handlers with one of our own, we can redirect execution to any place we like. This could be helpful in situations where we have a stack canary guarding the ret value or where the app makes some kind of custom smash control. Therefore, in the case of the filename, we will overwrite the exception handling record to point back to our buffer and then keep writing past the boundaries of the thread's stack, raising an access violation. Once this exception is triggered, the application will look for a valid handler in our stack and our bogus handler will be called. And that's all there is to it. We could also go for a traditional ret overwrite but appart from the fact that we can learn a new trick, for this to happen we would have to modify our pdf file so that the offset of the aforementioned xref and trailer sections would fit properly. I tried using Didier Stevens's pdf creating modules for python but I didn't manage to get a properly working pdf :P Anyways, I hope you enjoyed this establishment and that I can see you soon here again. Till then, may the force be with you! :)