CVE-2019-9588: Invalid memory access in gAtomicIncrement( ) – xpdf-4.01

Invalid memory access in GAtomicCounter gAtomicIncrement( ) – xpdf-4.01

Loginsoft-2019-1102

26 February, 2019

CVE Number

CVE-2019-9588

CWE

CWE-119: Improper Restriction of Operations within the Bounds of a Memory Buffer

Product Details

Xpdf is a free PDF viewer and toolkit, including a text extractor, image converter, HTML converter, and more. Most of the tools are available as open source.
URL: https://www.xpdfreader.com/download.html

Vulnerable Versions

4.01

Vulnerability Details

During our research there is aInvalid memory access in GAtomicCounter gAtomicIncrement( ) located at GMutex.h in xpdf-4.01. The same be triggered by sending a crafted pdf file to the pdftops binary. It allows an attacker to cause Denial of Service (Segmentation fault) or possibly have unspecified other impact.

SYNOPSIS

In Progress

Vulnerable Source Code
static inline GAtomicCounter gAtomicIncrement(GAtomicCounter *counter) {
 GAtomicCounter newVal;
Analysis

DEBUG:
GDB:

[ Legend: Modified register | Code | Heap | Stack | String ]
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$rax   : 0x000060400000c5f0  →  0x0000000000015519
$rbx   : 0x0000611000009c80  →  0x000060700000dfb0  →  0x000060200000fed0  →  0xbebebebe00000008
$rcx   : 0x00007fffff7ff1b0  →  0x0000000000000007
$rdx   : 0x000060400000c5d0  →  0x000061d00001cc80  →  0x000061300000de80  →  0x00000000005b1dc8  →  0x0000000000518dd8  →  <FileStream::~FileStream()+0> push rbp
$rsp   : 0x00007fffff7ff000  →  0x000000000049d89c  →  <Dict::incRef()+28> leave 
$rbp   : 0x00007fffff7ff010  →  0x00007fffff7ff030  →  0x00007fffff7ff0e0  →  0x00007fffff7ff110  →  0x00007fffff7ff140  →  0x00007fffff7ff170  →  0x00007fffff7ff1d0  →  0x00007fffff7ff230
$rsi   : 0x00007fffff7ff1b0  →  0x0000000000000007
$rdi   : 0x000060400000c5f0  →  0x0000000000015519
$rip   : 0x000000000049d220  →  <_ZL16gAtomicIncrementPl+0> push rbp
$r8    : 0x000061d00001d4d8  →  0x0000000000000001
$r9    : 0x1aefa           
$r10   : 0x80              
$r11   : 0x00007ffff7e41ef8  →  0x0000000000000000
$r12   : 0x000000000044ca40  →  <_start+0> xor ebp, ebp
$r13   : 0x00007fffffffde30  →  0x0000000000000012
$r14   : 0x0               
$r15   : 0x0               
$eflags: [carry PARITY adjust zero sign trap INTERRUPT direction overflow RESUME virtualx86 identification]
$cs: 0x0033 $ss: 0x002b $ds: 0x0000 $es: 0x0000 $fs: 0x0000 $gs: 0x0000 
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0x00007fffff7ff000│+0x0000: 0x000000000049d89c  →  <Dict::incRef()+28> leave      ← $rsp
0x00007fffff7ff008│+0x0008: 0x000060400000c5d0  →  0x000061d00001cc80  →  0x000061300000de80  →  0x00000000005b1dc8  →  0x0000000000518dd8  →  <FileStream::~FileStream()+0> push rbp
0x00007fffff7ff010│+0x0010: 0x00007fffff7ff030  →  0x00007fffff7ff0e0  →  0x00007fffff7ff110  →  0x00007fffff7ff140  →  0x00007fffff7ff170  →  0x00007fffff7ff1d0  →  0x00007fffff7ff230     ← $rbp
0x00007fffff7ff018│+0x0018: 0x000000000050953f  →  <Object::copy(Object*)+163> jmp 0x50958b <Object::copy(Object*)+239>
0x00007fffff7ff020│+0x0020: 0x00007fffff7ff1b0  →  0x0000000000000007
0x00007fffff7ff028│+0x0028: 0x000061d00001d360  →  0x0000000000000007
0x00007fffff7ff030│+0x0030: 0x00007fffff7ff0e0  →  0x00007fffff7ff110  →  0x00007fffff7ff140  →  0x00007fffff7ff170  →  0x00007fffff7ff1d0  →  0x00007fffff7ff230  →  0x00007fffff7ff290
0x00007fffff7ff038│+0x0038: 0x000000000053a6f8  →  <XRef::fetch(int,+0> mov rax, QWORD PTR [rbp-0x88]
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
     0x49d21a <DecryptStream::getUndecodedStream()+8> mov    rax, QWORD PTR [rbp-0x8]
     0x49d21e <DecryptStream::getUndecodedStream()+12> pop    rbp
     0x49d21f <DecryptStream::getUndecodedStream()+13> ret    
→   0x49d220 <_ZL16gAtomicIncrementPl+0> push   rbp
     0x49d221 <_ZL16gAtomicIncrementPl+1> mov    rbp, rsp
     0x49d224 <_ZL16gAtomicIncrementPl+4> mov    QWORD PTR [rbp-0x18], rdi
     0x49d228 <_ZL16gAtomicIncrementPl+8> mov    rdx, QWORD PTR [rbp-0x18]
     0x49d22c <_ZL16gAtomicIncrementPl+12> mov    eax, 0x1
     0x49d231 <_ZL16gAtomicIncrementPl+17> lock   xadd QWORD PTR [rdx], rax
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── source:/home/aceteam/Downloads/sources/xpdf-4.01/goo/GMutex.h+66 ────
     61     // NB: this must be "long" to work on Windows
     62     typedef long GAtomicCounter;
     63     
     64     // Increment *counter by one and return the final value (after the
     65     // increment).
        // counter=0x00007fffff7fefe0
→   66     static inline GAtomicCounter gAtomicIncrement(GAtomicCounter *counter) {
     67       GAtomicCounter newVal;
     68     
     69     #if defined(_WIN32)
     70       newVal = _InterlockedIncrement(counter);
     71     #elif defined(__GNUC__) || defined(__xlC__)
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "pdftops", stopped, reason: SIGSEGV
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[!] Cannot access memory at address 0x7fffff7fefe0

gef➤  ptype counter
type = long *
gef➤  p/d 0x7fffff7fefe0
$2 = 140737479962592
gef➤  x *counter
Cannot access memory at address 0x7fffff7fefe0
 
Proof of Concept

pdftops -f 2 -l 4 -level2 -noembt1 -preload -nocrop -noshrink -nocenter -pagecrop -userunit -duplex -upw rome $POC out.ps
POC FILE: REPRODUCER
Vendor Disclosure: 2019-2-26
Public Disclosure:

Credit

Discovered by ACE Team – Loginsoft