Invalid memory access in TextPage::findGaps() – xpdf-4.01
13 March, 2019
CVE Number
CVE-2019-9877
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 we discovered invalid memory access vulnerability in function TextPage::findGaps() located at TextOutputDev.c 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
for (y = yMinI2; y <= yMaxI2; ++y) { ++horizProfile[y - yMinI]; }
Analysis
DEBUG:
GDB :
[ Legend: Modified register | Code | Heap | Stack | String ] ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ──── $rax : 0x0000601e00028878 → 0x0000000000000000 $rbx : 0x000060300001ef40 → 0x0000606000002600 → 0xbebebebebebebebe $rcx : 0x0 $rdx : 0xfffffffe00001888 $rsp : 0x00007fffffffd580 → 0x00007fffffffd6e8 → 0xfff8000000000000 $rbp : 0x00007fffffffd660 → 0x00007fffffffd7c0 → 0x00007fffffffd850 → 0x00007fffffffd910 → 0x00007fffffffd9b0 → 0x00007fffffffd9d0 → 0x00007fffffffda10 → 0x00007fffffffdb00 $rsi : 0x34 $rdi : 0x000060300001efa0 → 0x0000625000005100 → 0x000060800000bf20 → 0x0000000100000041 → 0x0000000000000000 $rip : 0x0000000000449cee → mov edx, DWORD PTR [rax] $r8 : 0x00007ffff7fd3778 → 0x0000000000000000 $r9 : 0x15440 $r10 : 0x0000602000026fd0 → 0x0000003400000000 → 0x0000000000000000 $r11 : 0x00007ffff7f22250 → 0x0000000000000000 $r12 : 0x00007fffffffdab0 → 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 ──── 0x00007fffffffd580│+0x0000: 0x00007fffffffd6e8 → 0xfff8000000000000 ← $rsp 0x00007fffffffd588│+0x0008: 0x00007fffffffd6e0 → 0xfff8000000000000 0x00007fffffffd590│+0x0010: 0x00007fffffffd6d8 → 0xfff8000000000000 0x00007fffffffd598│+0x0018: 0x00000000000080a0 0x00007fffffffd5a0│+0x0020: 0x000060300001efa0 → 0x0000625000005100 → 0x000060800000bf20 → 0x0000000100000041 → 0x0000000000000000 0x00007fffffffd5a8│+0x0028: 0x0000611000009280 → 0x0000000000000003 0x00007fffffffd5b0│+0x0030: 0x000060800000ba20 → 0x0000000e00000046 → 0x0000000000000000 0x00007fffffffd5b8│+0x0038: 0x0000062100000005 → 0x0000000000000000 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ──── 0x449cdf lea rdx, [rax*4+0x0] 0x449ce7 mov rax, QWORD PTR [rbp-0x38] 0x449ceb add rax, rdx → 0x449cee mov edx, DWORD PTR [rax] 0x449cf0 add edx, 0x1 0x449cf3 mov DWORD PTR [rax], edx 0x449cf5 add DWORD PTR [rbp-0x90], 0x1 0x449cfc jmp 0x449cc3 0x449cfe mov eax, DWORD PTR [rbp-0xa8] ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── source:/home/aceteam/Desktop/xpdf-4.01/xpdf/TextOutputDev.cc+3097 ──── 3092 yMinI2 = (int)floor(ch->yMin / splitPrecision); 3093 yMaxI2 = (int)floor(ch->yMax / splitPrecision); 3094 break; 3095 } 3096 for (y = yMinI2; y <= yMaxI2; ++y) { // horizProfile=0x00007fffffffd628 → [...] → 0x0000000000000000, yMinI=0x7fffffff, y=0x621 → 3097 ++horizProfile[y - yMinI]; 3098 } 3099 for (x = xMinI2; x <= xMaxI2; ++x) { 3100 ++vertProfile[x - xMinI]; 3101 } 3102 } ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ──── [#0] Id 1, Name: "pdftotext", stopped, reason: SIGSEGV ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ──── [#0] 0x449cee → TextPage::findGaps(this=0x611000009280, charsA=0x60300001efa0, rot=0x0, xMinOut=0x7fffffffd6d8, yMinOut=0x7fffffffd6e0, xMaxOut=0x7fffffffd6e8, yMaxOut=0x7fffffffd6f0, avgFontSizeOut=0x7fffffffd6f8, horizGaps=0x60300001ef70, vertGaps=0x60300001ef40) [#1] 0x44841e → TextPage::split(this=0x611000009280, charsA=0x60300001efa0, rot=0x0) [#2] 0x44818d → TextPage::splitChars(this=0x611000009280, charsA=0x603000001870) [#3] 0x443fb4 → TextPage::writePhysLayout(this=0x611000009280, outputStream=0x61600000f380, outputFunc=0x44f988 , uMap=0x60600000d520, space=0x7fffffffd970 " \331\377\377\377\177", spaceLen=0x1, eol=0x7fffffffd990 "\n", eolLen=0x1) [#4] 0x443932 → TextPage::write(this=0x611000009280, outputStream=0x61600000f380, outputFunc=0x44f988 ) [#5] 0x44ff13 → TextOutputDev::endPage(this=0x610000007f40) [#6] 0x479901 → Gfx::~Gfx(this=0x60f00000e9b0, __in_chrg=) [#7] 0x4e319f → Page::displaySlice(this=0x60800000bfa0, out=0x610000007f40, hDPI=72, vDPI=72, rotate=0x0, useMediaBox=0x0, crop=0x0, sliceX=0xffffffff, sliceY=0xffffffff, sliceW=0xffffffff, sliceH=0xffffffff, printing=0x0, abortCheckCbk=0x0, abortCheckCbkData=0x0) [#8] 0x4e2b57 → Page::display(this=0x60800000bfa0, out=0x610000007f40, hDPI=72, vDPI=72, rotate=0x0, useMediaBox=0x0, crop=0x1, printing=0x0, abortCheckCbk=0x0, abortCheckCbkData=0x0) [#9] 0x4e7bb7 → PDFDoc::displayPage(this=0x60700000dfb0, out=0x610000007f40, page=0x1, hDPI=72, vDPI=72, rotate=0x0, useMediaBox=0x0, crop=0x1, printing=0x0, abortCheckCbk=0x0, abortCheckCbkData=0x0) gef➤ ptype ++horizProfile[y - yMinI] type = int gef➤ ptype horizProfile type = int * gef➤ p/d y $24 = 1569 gef➤ p/d yMinI $25 = 2147483647 gef➤ x ++horizProfile[y - yMinI] 0x1: Cannot access memory at address 0x1
Proof of Concept
pdftotext -f 1 -l 4 -layout -simple -table -lineprinter -raw -fixed 2 -clip -nodiag -upw rome $POC out.txt
POC FILE: REPRODUCER
Vendor Disclosure: 2019-3-13
Public Disclosure: 2019-3-20
Credit
Discovered by ACE Team – Loginsoft