Talos Vulnerability Report

TALOS-2018-0525

Foxit PDF Reader JavaScript setPersistent Remote Code Execution Vulnerability

April 19, 2018
CVE Number

CVE-2018-3842

Summary

An exploitable use of an uninitialized pointer vulnerability exists in the JavaScript engine in Foxit PDF Reader version 9.0.1.1049. A specially crafted PDF document can lead to a dereference of an uninitialized pointer which, if under attacker control, can result in arbitrary code execution. An attacker needs to trick the user to open a 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.0.1.1049

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-457: Use of Uninitialized Variable

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 posses an additional attack surface. Additionally, Foxit PDF Reader supports XFA or XML Forms Architecture which is a new way of making interactive PDF forms.

When processing a specially crafted PDF document that contains XFA forms, executing the following JavaScript code leads to a dereference of an uninitialized pointer:

this.global.setPersistent(); 

This results in the following crash:

eax=000027f6 ebx=c0c0c0c0 ecx=c0c0c0c0 edx=0020eba8 esi=0020eb34 edi=0020eba8
eip=0151be10 esp=0020eac8 ebp=0020eaec iopl=0         nv up ei ng nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00210286
FoxitReader!CertFreeCertificateChain+0x16fa30:
0151be10 8b4104          mov     eax,dword ptr [ecx+4] ds:0023:c0c0c0c4=????????

Note that 0xc0c0c0c0 is a PageHeap magic value for allocated but uninitialized memory. Tracking back to see where this pointer in ecx comes from reveals the following:

0:000> bp  FoxitReader!CertFreeCertificateChain+0x10d5a0
0:000> g
eax=12fdcff0 ebx=00000000 ecx=1323ef68 edx=0022e520 esi=13c3efb8 edi=123c2ff8
eip=018f9980 esp=0022e474 ebp=0022e4a0 iopl=0         nv up ei ng nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200282
FoxitReader!CertFreeCertificateChain+0x10d5a0:
018f9980 e8db09f0ff      call    FoxitReader!CertFreeCertificateChain+0xdf80 (017fa360)
0:000> u 017fa360
FoxitReader!CertFreeCertificateChain+0xdf80:
017fa360 8b416c          mov     eax,dword ptr [ecx+6Ch]
017fa363 c3              ret
0:000> dd ecx+6c
1323efd4  c0c0c0c0 00000000 00000001 106a8ff8
1323efe4  00000000 00000000 00000000 00000000
1323eff4  c0c0c0c0 00000000 00000000 ????????
1323f004  ???????? ???????? ???????? ????????
1323f014  ???????? ???????? ???????? ????????
1323f024  ???????? ???????? ???????? ????????
1323f034  ???????? ???????? ???????? ????????
1323f044  ???????? ???????? ???????? ????????

In the above output, we can see that at FoxitReader!CertFreeCertificateChain+0x10d5a0 a call is being made to a simple dereferencing function, which grabs a pointer from ecx+0x6c and puts it into eax. As we can see from the memory output, this pointer is uninitialized. The object pointed to by ecx is actually allocated:

0:000> !heap -p -a ecx
    address 1323ef68 found in
    _DPH_HEAP_ROOT @ 7431000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                                130f298c:         1323ef68               98 -         1323e000             2000
          ? FoxitReader!CertFreeCertificateChain+186dd2c
    57a08e89 verifier!AVrfDebugPageHeapAllocate+0x00000229
    77276206 ntdll!RtlDebugAllocateHeap+0x00000030
    7723a127 ntdll!RtlpAllocateHeap+0x000000c4
    77205950 ntdll!RtlAllocateHeap+0x0000023a
    02b8ee12 FoxitReader!CertFreeCertificateChain+0x013a2a32
    029d96ea FoxitReader!CertFreeCertificateChain+0x011ed30a
    017ec6dc FoxitReader!CertFreeCertificateChain+0x000002fc
    017f0142 FoxitReader!CertFreeCertificateChain+0x00003d62
    01226aef FoxitReader+0x00136aef
    01309bce FoxitReader+0x00219bce
    012d8083 FoxitReader+0x001e8083
    012e3697 FoxitReader+0x001f3697
    012cb074 FoxitReader+0x001db074
    012cfa5c FoxitReader+0x001dfa5c
    02cee5af FoxitReader!CertFreeCertificateChain+0x015021cf
    02b889ca FoxitReader!CertFreeCertificateChain+0x0139c5ea
    75dcef8c kernel32!BaseThreadInitThunk+0x0000000e
    7721367a ntdll!__RtlUserThreadStart+0x00000070
    7721364d ntdll!_RtlUserThreadStart+0x0000001b

Further on, the pointer from eax ends up in ebx and ends up being used as this pointer in a thiscall function call:

.text:00C09996 lea     eax, [ebp+arg_4]
.text:00C09999 push    27F6h
.text:00C0999E push    eax
.text:00C0999F mov     ecx, ebx
.text:00C099A1 call    sub_C095C0 

Finally, the crash will happen when the uninitialized this value is used to dereference a vtable in the function sub_C095C0:

.text:00C095F3 mov eax, [ebp+arg_4] .text:00C095F6 push eax .text:00C095F7 call sub_C6BE10 .text:00C095FC push esi .text:00C095FD mov edi, eax .text:00C095FF call sub_C094E0 .text:00C09604 add esp, 8 .text:00C09607 jmp short loc_

The crash actually occurs in the sub_C6BE10 call, comprised of just two instructions, that perform an object table dereference:

.text:00C6BE10 sub_C6BE10 proc near
.text:00C6BE10 mov     eax, [ecx+4]
.text:00C6BE13 mov     eax, [eax+3Ch]
.text:00C6BE16 retn
.text:00C6BE16 sub_C6BE10 endp
.text:00C6BE16

The target of double dereference above ends up in eax. If we follow this value through registers, it ends up being saved in edi, which is later dereferenced again into eax and is used as the destination of an indirect call:

.text:00C09560 mov     eax, [edi]
.text:00C09562 push    esi
.text:00C09563 lea     edx, [ebp+var_18]
.text:00C09566 push    edx
.text:00C09567 mov     byte ptr [ebp+var_4], 1
.text:00C0956B mov     eax, [eax+11Ch]
.text:00C09571 mov     ecx, edi
.text:00C09573 call    eax

Following this, we can conclude that if, with careful memory layout manipulation, an attacker can control the contents of memory that gets used uninitialized it will eventually lead to control of the contents of eax at the above call instruction leading to arbitrary code execution.

Crash Information

(edc.14c4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=000027f6 ebx=c0c0c0c0 ecx=c0c0c0c0 edx=0022e520 esi=0022e4ac edi=0022e520
eip=0195be10 esp=0022e440 ebp=0022e464 iopl=0         nv up ei ng nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00210286
FoxitReader!CertFreeCertificateChain+0x16fa30:
0195be10 8b4104          mov     eax,dword ptr [ecx+4] ds:0023:c0c0c0c4=????????
0:000> k
 # ChildEBP RetAddr  
WARNING: Stack unwind information not available. Following frames may be wrong.
00 0022e464 018f99a6 FoxitReader!CertFreeCertificateChain+0x16fa30
01 0022e4a0 018f9bf9 FoxitReader!CertFreeCertificateChain+0x10d5c6
02 0022e4fc 014391c8 FoxitReader!CertFreeCertificateChain+0x10d819
03 0022e544 02836e8e FoxitReader+0x3491c8
04 0022e578 0282ec76 FoxitReader!CertFreeCertificateChain+0x104aaae
05 0022e5e0 02831023 FoxitReader!CertFreeCertificateChain+0x1042896
06 0022e5f0 1770a0d6 FoxitReader!CertFreeCertificateChain+0x1044c43
07 0022e610 1774db1a 0x1770a0d6
08 0022e630 17738e95 0x1774db1a
09 0022e64c 17722aca 0x17738e95
0a 0022e688 027270c9 0x17722aca
0b 0022e6d0 02727c0b FoxitReader!CertFreeCertificateChain+0xf3ace9
0c 0022e708 02683f61 FoxitReader!CertFreeCertificateChain+0xf3b82b
0d 0022e760 0143b0a2 FoxitReader!CertFreeCertificateChain+0xe97b81
0e 0022e7ec 0143a6f6 FoxitReader+0x34b0a2
0f 0022e7fc 0195c202 FoxitReader+0x34a6f6
10 0022e860 0195c462 FoxitReader!CertFreeCertificateChain+0x16fe22
11 0022e874 016af278 FoxitReader!CertFreeCertificateChain+0x170082
12 0022e8a4 016b2166 FoxitReader+0x5bf278
13 0022e8dc 016b2e4f FoxitReader+0x5c2166
14 0022e934 011c2a3a FoxitReader+0x5c2e4f
15 0022e96c 01324ae0 FoxitReader+0xd2a3a
16 0022f580 029e8172 FoxitReader+0x234ae0
17 0022f638 029e24f9 FoxitReader!CertFreeCertificateChain+0x11fbd92
18 0022f658 029e63fc FoxitReader!CertFreeCertificateChain+0x11f6119
19 0022f6cc 029e648b FoxitReader!CertFreeCertificateChain+0x11fa01c
1a 0022f6ec 756ac4b7 FoxitReader!CertFreeCertificateChain+0x11fa0ab
1b 0022f718 756ac5b7 USER32!InternalCallWinProc+0x23
1c 0022f790 756acbe9 USER32!UserCallWinProcCheckWow+0x14b
1d 0022f7f0 756acc40 USER32!DispatchMessageWorker+0x357
1e 0022f800 029e0596 USER32!DispatchMessageW+0xf
1f 0022f830 02cee5d0 FoxitReader!CertFreeCertificateChain+0x11f41b6
20 0022f844 02b889ca FoxitReader!CertFreeCertificateChain+0x15021f0
21 0022f8d4 75dcef8c FoxitReader!CertFreeCertificateChain+0x139c5ea
22 0022f8e0 7721367a kernel32!BaseThreadInitThunk+0xe
23 0022f920 7721364d ntdll!__RtlUserThreadStart+0x70
24 0022f938 00000000 ntdll!_RtlUserThreadStart+0x1b

Timeline

2018-02-12 - Vendor Disclosure
2018-02-14 - Discussion with vendor on issues
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.