NULL POINTER DEREFERENCE Vulnerability in function PSOutputDev::setupResources( ) - xpdf-4.01
Loginsoft-2019-1103
27 February, 2019
CVE Number
CVE-2019-9589
CWE
CWE-476: NULL Pointer Dereference
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 a null pointer dereference vulnerability, in PSOutputDev::setupResources( )
located in PSOutputDev.cc 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
if ((gsDict.dictGetValNF(i, &gsRef)->isRef())) {
ref0 = gsRef.getRef();
→ skip = (GBool)visitedResources[ref0.num];
visitedResources[ref0.num] = 1;
}
Analysis
DEBUG:
GDB:
[ Legend: Modified register | Code | Heap | Stack | String ]
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$rax : 0x0000602fa004e880 → 0x0000000000000000
$rbx : 0x000060300004e820 → 0x000060705b800009 → 0x0000000000000000
$rcx : 0x00007fffffffda30 → 0x000060f000000009 → 0x0000000000000000
$rdx : 0x000060300004e880 → 0x0000000000000000
$rsp : 0x00007fffffffd990 → 0x000060400000d3d0 → 0x000061d00001cc80 → 0x000061300000de80 → 0x00000000005b1dc8 → 0x0000000000518dd8 → push rbp
$rbp : 0x00007fffffffda90 → 0x00007fffffffdb40 → 0x00007fffffffdbe0 → 0x00007fffffffdc80 → 0x00007fffffffdd50 → 0x000000000058efd0 → push r15
$rsi : 0x00007fffffffda30 → 0x000060f000000009 → 0x0000000000000000
$rdi : 0x00007fffffffda30 → 0x000060f000000009 → 0x0000000000000000
$rip : 0x0000000000451b2d → movzx eax, BYTE PTR [rax]
$r8 : 0x0
$r9 : 0x185d1
$r10 : 0x58
$r11 : 0x00007ffff7f1d820 → 0x0000000000000000
$r12 : 0x00007fffffffdaf0 → 0xbebebebe0000000d
$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 ────
0x00007fffffffd990│+0x0000: 0x000060400000d3d0 → 0x000061d00001cc80 → 0x000061300000de80 → 0x00000000005b1dc8 → 0x0000000000518dd8 → push rbp ← $rsp
0x00007fffffffd998│+0x0008: 0x0000616000002180 → 0x0000000000595a68 → 0x000000000044fa1e → push rbp
0x00007fffffffd9a0│+0x0010: 0x000060c000007840 → 0x000000004a000006
0x00007fffffffd9a8│+0x0018: 0x0000000000000000
0x00007fffffffd9b0│+0x0020: 0x00000000a0000000 → 0x0000000000000000
0x00007fffffffd9b8│+0x0028: 0x000000000050ee6f → add rsp, 0x30
0x00007fffffffd9c0│+0x0030: 0xffffffff0000000d
0x00007fffffffd9c8│+0x0038: 0x00007ffff5da9242 → mov QWORD PTR [rbx+0x28], rax
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
0x451b21 add BYTE PTR [rbx-0xdf7b], cl
0x451b27 dec DWORD PTR [rax-0x68]
0x451b2a add rax, rdx
→ 0x451b2d movzx eax, BYTE PTR [rax]
0x451b30 movsx eax, al
0x451b33 mov DWORD PTR [rbp-0xe8], eax
0x451b39 mov rax, QWORD PTR [rbp-0xf8]
0x451b40 mov rdx, QWORD PTR [rax+0x138]
0x451b47 mov eax, DWORD PTR [rbp-0xe0]
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── source:/home/aceteam/Downloads/sources/xpdf-4.01/xpdf/PSOutputDev.cc+1991 ────
1986
1987 // check for an already-visited ExtGState
1988 skip = gFalse;
1989 if ((gsDict.dictGetValNF(i, &gsRef)->isRef())) {
1990 ref0 = gsRef.getRef();
→ 1991 skip = (GBool)visitedResources[ref0.num];
1992 visitedResources[ref0.num] = 1;
1993 }
1994 if (!skip) {
1995
1996 // process the ExtGState's SMask's transparency group's resource dict
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "pdftops", stopped, reason: SIGSEGV
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x451b2d → PSOutputDev::setupResources(this=0x616000002180, resDict=0x60400000d3d0)
[#1] 0x450cdc → PSOutputDev::writeDocSetup(this=0x616000002180, catalog=0x611000008880)
[#2] 0x44f990 → PSOutputDev::init(this=0x616000002180, outputFuncA=0x44eb56 , outputStreamA=0x616000001e80, fileTypeA=psFile, docA=0x60700000dfb0, firstPageA=0x2, lastPageA=0x4, modeA=psModePS, imgLLXA=0x0, imgLLYA=0x0, imgURXA=0x0, imgURYA=0x0, manualCtrlA=0x0, honorUserUnitA=0x1)
[#3] 0x44ee44 → PSOutputDev::PSOutputDev(this=0x616000002180, fileName=0x60200004e290 "out.ps", docA=0x60700000dfb0, firstPageA=0x2, lastPageA=0x4, modeA=psModePS, imgLLXA=0x0, imgLLYA=0x0, imgURXA=0x0, imgURYA=0x0, manualCtrlA=0x0, customCodeCbkA=0x0, customCodeCbkDataA=0x0, honorUserUnitA=0x1)
[#4] 0x47dbbc → main(argc=0x3, argv=0x7fffffffde38)
gef➤ ptype visitedResources
type = char *
gef➤ x visitedResources[0]
0x0: Cannot access memory at address 0x0
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
Timeline
Vendor Disclosure: 2019-2-27
Public Disclosure: 2019-3-6
Credit
Discovered by ACE Team - Loginsoft