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! :)