/
/
/
CVE-2019-9200: Heap based Buffer Underwrite in ImageStream::getLine() - poppler 0.74.0

CVE-2019-9200: Heap based Buffer Underwrite in ImageStream::getLine() - poppler 0.74.0

Vulnerability Reports
February 26, 2019
Profile Icon

Jason Franscisco

Heap based Buffer Underwrite in ImageStream::getLine() - poppler 0.74.0

Loginsoft-2019-1098

26 February, 2019

CVE Number

CVE-2019-9200

CWE

CWE-124: Buffer Underwrite.

Product Details

Poppler is a free software utility library for rendering Portable Document Format documents.

‍URL: Gitlab

Vulnerable Versions

0.74.0

Vulnerability Details

During our research there is a Heap based Buffer Underwrite in ImageStream::getLine() located at Stream.cc in poppler 0.74.0. The same be triggered by sending a crafted pdf file to the pdfimages binary. It allows an attacker to cause Denial of Service (Segmentation fault) or possibly have unspecified other impact.

SYNOPSIS

When a crafted pdf file is passed to the binary, we observed in the function ImageOutputDev::writeImage() at line writeImageFile(writer, format,format == imgRGB ? "ppm" : "pbm",str, width, height, colorMap); here writeImageFile calls to another function ImageOutputDev::writeImageFile() here at the line p = imgStr->getLine(); now this line invokes to another function ImageStream::getLine(), here in the line for ( ; readChars < inputLineSize; readChars++) inputLine[readChars] = EOF; where readchars contains a negative value which is readChars=-0x1. So, when inputline[readChars]=EOF,readChar consists of negative value in which EOF is passed, triggering a heap based underwrite vulnerability.

Vulnerable Source code

  if (unlikely(inputLine == nullptr)) {
return nullptr;
}
int readChars = str->doGetChars(inputLineSize, inputLine);
for ( ; readChars < inputLineSize; readChars++) inputLine[readChars] = EOF;
if (nBits == 1) {
unsigned char *p = inputLine;
for (int i = 0; i < nVals; i += 8) {
const int c = *p++;
  
Analysis

DEBUG:

ASAN OUTPUT:


  =================================================================
==5771==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x603000010b3f at pc 0x7ffff67e3c20 bp 0x7fffffffa9d0 sp 0x7fffffffa9c0
WRITE of size 1 at 0x603000010b3f thread T0
#0 0x7ffff67e3c1f in ImageStream::getLine() /home/aceteam/Desktop/packages/poppler-master/poppler/Stream.cc:499
#1 0x55555556334a in ImageOutputDev::writeImageFile(ImgWriter*, ImageOutputDev::ImageFormat, char const*, Stream*, int, int, GfxImageColorMap*) /home/aceteam/Desktop/packages/poppler-master/utils/ImageOutputDev.cc:410
#2 0x555555565939 in ImageOutputDev::writeImage(GfxState*, Object*, Stream*, int, int, GfxImageColorMap*, bool) /home/aceteam/Desktop/packages/poppler-master/utils/ImageOutputDev.cc:666
#3 0x555555565b95 in ImageOutputDev::drawImage(GfxState*, Object*, Stream*, int, int, GfxImageColorMap*, bool, int*, bool) /home/aceteam/Desktop/packages/poppler-master/utils/ImageOutputDev.cc:702
#4 0x7ffff6667e1b in Gfx::doImage(Object*, Stream*, bool) /home/aceteam/Desktop/packages/poppler-master/poppler/Gfx.cc:4593
#5 0x7ffff666b5f9 in Gfx::opBeginImage(Object*, int) /home/aceteam/Desktop/packages/poppler-master/poppler/Gfx.cc:4897
#6 0x7ffff6636a48 in Gfx::execOp(Object*, Object*, int) /home/aceteam/Desktop/packages/poppler-master/poppler/Gfx.cc:876
#7 0x7ffff6635b3e in Gfx::go(bool) /home/aceteam/Desktop/packages/poppler-master/poppler/Gfx.cc:752
#8 0x7ffff6635590 in Gfx::display(Object*, bool) /home/aceteam/Desktop/packages/poppler-master/poppler/Gfx.cc:714
#9 0x7ffff666b09e in Gfx::drawForm(Object*, Dict*, double const*, double const*, bool, bool, GfxColorSpace*, bool, bool, bool, Function*, GfxColor*) /home/aceteam/Desktop/packages/poppler-master/poppler/Gfx.cc:4841
#10 0x7ffff6669ca4 in Gfx::doForm(Object*) /home/aceteam/Desktop/packages/poppler-master/poppler/Gfx.cc:4764
#11 0x7ffff6662f75 in Gfx::opXObject(Object*, int) /home/aceteam/Desktop/packages/poppler-master/poppler/Gfx.cc:4181
#12 0x7ffff6636a48 in Gfx::execOp(Object*, Object*, int) /home/aceteam/Desktop/packages/poppler-master/poppler/Gfx.cc:876
#13 0x7ffff6635b3e in Gfx::go(bool) /home/aceteam/Desktop/packages/poppler-master/poppler/Gfx.cc:752
#14 0x7ffff6635590 in Gfx::display(Object*, bool) /home/aceteam/Desktop/packages/poppler-master/poppler/Gfx.cc:714
#15 0x7ffff6762e8d in Page::displaySlice(OutputDev*, double, double, int, bool, bool, int, int, int, int, bool, bool (*)(void*), void*, bool (*)(Annot*, void*), void*, bool) /home/aceteam/Desktop/packages/poppler-master/poppler/Page.cc:548
#16 0x7ffff6762354 in Page::display(OutputDev*, double, double, int, bool, bool, bool, bool (*)(void*), void*, bool (*)(Annot*, void*), void*, bool) /home/aceteam/Desktop/packages/poppler-master/poppler/Page.cc:469
#17 0x7ffff676dac9 in PDFDoc::displayPage(OutputDev*, int, double, double, int, bool, bool, bool, bool (*)(void*), void*, bool (*)(Annot*, void*), void*, bool) /home/aceteam/Desktop/packages/poppler-master/poppler/PDFDoc.cc:633
#18 0x7ffff676db63 in PDFDoc::displayPages(OutputDev*, int, int, double, double, int, bool, bool, bool, bool (*)(void*), void*, bool (*)(Annot*, void*), void*) /home/aceteam/Desktop/packages/poppler-master/poppler/PDFDoc.cc:650
#19 0x555555560c93 in main /home/aceteam/Desktop/packages/poppler-master/utils/pdfimages.cc:220
#20 0x7ffff5abeb96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
#21 0x55555555f129 in _start (/usr/local/bin/pdfimages+0xb129)


0x603000010b3f is located 1 bytes to the left of 30-byte region [0x603000010b40,0x603000010b5e)
allocated by thread T0 here:
#0 0x7ffff6ef8b50 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb50)
#1 0x555555565ed4 in gmalloc(unsigned long, bool) /home/aceteam/Desktop/packages/poppler-master/goo/gmem.h:41
#2 0x5555555660f2 in gmallocn(int, int, bool) (/usr/local/bin/pdfimages+0x120f2)
#3 0x7ffff662f66b in gmallocn_checkoverflow(int, int) /home/aceteam/Desktop/packages/poppler-master/goo/gmem.h:119
#4 0x7ffff67e33a3 in ImageStream::ImageStream(Stream*, int, int, int) /home/aceteam/Desktop/packages/poppler-master/poppler/Stream.cc:446
#5 0x555555563175 in ImageOutputDev::writeImageFile(ImgWriter*, ImageOutputDev::ImageFormat, char const*, Stream*, int, int, GfxImageColorMap*) /home/aceteam/Desktop/packages/poppler-master/utils/ImageOutputDev.cc:381
#6 0x555555565939 in ImageOutputDev::writeImage(GfxState*, Object*, Stream*, int, int, GfxImageColorMap*, bool) /home/aceteam/Desktop/packages/poppler-master/utils/ImageOutputDev.cc:666
#7 0x555555565b95 in ImageOutputDev::drawImage(GfxState*, Object*, Stream*, int, int, GfxImageColorMap*, bool, int*, bool) /home/aceteam/Desktop/packages/poppler-master/utils/ImageOutputDev.cc:702
#8 0x7ffff6667e1b in Gfx::doImage(Object*, Stream*, bool) /home/aceteam/Desktop/packages/poppler-master/poppler/Gfx.cc:4593
#9 0x7ffff666b5f9 in Gfx::opBeginImage(Object*, int) /home/aceteam/Desktop/packages/poppler-master/poppler/Gfx.cc:4897
#10 0x7ffff6636a48 in Gfx::execOp(Object*, Object*, int) /home/aceteam/Desktop/packages/poppler-master/poppler/Gfx.cc:876
#11 0x7ffff6635b3e in Gfx::go(bool) /home/aceteam/Desktop/packages/poppler-master/poppler/Gfx.cc:752
#12 0x7ffff6635590 in Gfx::display(Object*, bool) /home/aceteam/Desktop/packages/poppler-master/poppler/Gfx.cc:714
#13 0x7ffff666b09e in Gfx::drawForm(Object*, Dict*, double const*, double const*, bool, bool, GfxColorSpace*, bool, bool, bool, Function*, GfxColor*) /home/aceteam/Desktop/packages/poppler-master/poppler/Gfx.cc:4841
#14 0x7ffff6669ca4 in Gfx::doForm(Object*) /home/aceteam/Desktop/packages/poppler-master/poppler/Gfx.cc:4764
#15 0x7ffff6662f75 in Gfx::opXObject(Object*, int) /home/aceteam/Desktop/packages/poppler-master/poppler/Gfx.cc:4181
#16 0x7ffff6636a48 in Gfx::execOp(Object*, Object*, int) /home/aceteam/Desktop/packages/poppler-master/poppler/Gfx.cc:876
#17 0x7ffff6635b3e in Gfx::go(bool) /home/aceteam/Desktop/packages/poppler-master/poppler/Gfx.cc:752
#18 0x7ffff6635590 in Gfx::display(Object*, bool) /home/aceteam/Desktop/packages/poppler-master/poppler/Gfx.cc:714
#19 0x7ffff6762e8d in Page::displaySlice(OutputDev*, double, double, int, bool, bool, int, int, int, int, bool, bool (*)(void*), void*, bool (*)(Annot*, void*), void*, bool) /home/aceteam/Desktop/packages/poppler-master/poppler/Page.cc:548
#20 0x7ffff6762354 in Page::display(OutputDev*, double, double, int, bool, bool, bool, bool (*)(void*), void*, bool (*)(Annot*, void*), void*, bool) /home/aceteam/Desktop/packages/poppler-master/poppler/Page.cc:469
#21 0x7ffff676dac9 in PDFDoc::displayPage(OutputDev*, int, double, double, int, bool, bool, bool, bool (*)(void*), void*, bool (*)(Annot*, void*), void*, bool) /home/aceteam/Desktop/packages/poppler-master/poppler/PDFDoc.cc:633
#22 0x7ffff676db63 in PDFDoc::displayPages(OutputDev*, int, int, double, double, int, bool, bool, bool, bool (*)(void*), void*, bool (*)(Annot*, void*), void*) /home/aceteam/Desktop/packages/poppler-master/poppler/PDFDoc.cc:650
#23 0x555555560c93 in main /home/aceteam/Desktop/packages/poppler-master/utils/pdfimages.cc:220
#24 0x7ffff5abeb96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)


SUMMARY: AddressSanitizer: heap-buffer-overflow /home/aceteam/Desktop/packages/poppler-master/poppler/Stream.cc:499 in ImageStream::getLine()
Shadow bytes around the buggy address:
0x0c067fffa110: 00 fa fa fa 00 00 00 fa fa fa fd fd fd fa fa fa
0x0c067fffa120: 00 00 00 fa fa fa 00 00 00 fa fa fa fd fd fd fa
0x0c067fffa130: fa fa fd fd fd fa fa fa fd fd fd fd fa fa 00 00
0x0c067fffa140: 00 fa fa fa 00 00 00 fa fa fa 00 00 00 fa fa fa
0x0c067fffa150: 00 00 00 fa fa fa 00 00 00 fa fa fa fd fd fd fd
=>0x0c067fffa160: fa fa 00 00 00 fa fa[fa]00 00 00 06 fa fa fa fa
0x0c067fffa170: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c067fffa180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c067fffa190: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c067fffa1a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c067fffa1b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07 
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==5771==ABORTING
  

GDB :


  for ( ; readChars < inputLineSize; readChars++) inputLine[readChars] = EOF;
[ Legend: Modified register | Code | Heap | Stack | String ]
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────[ registers ]────
$rax : 0xffffffff → 0x0000000000000000
$rbx : 0x7fffffffac50 → 0x00007fffffffac90 → 0x000000000000000a
$rcx : 0x0 
$rdx : 0x0 
$rsp : 0x7fffffffa9e0 → 0x00007fffffffaa30 → 0x00007fffffffac80 → 0x00007fffffffad40 → 0x00007fffffffad90 → 0x00007fffffffc380 → 0x00007fffffffc3c0 → 0x00007fffffffc420
$rbp : 0x7fffffffaa30 → 0x00007fffffffac80 → 0x00007fffffffad40 → 0x00007fffffffad90 → 0x00007fffffffc380 → 0x00007fffffffc3c0 → 0x00007fffffffc420 → 0x00007fffffffc850
$rsi : 0x3 
$rdi : 0x608000002120 → 0x00007ffff6d150a8 → 0x00007ffff67e8d36 →  push rbp
$rip : 0x7ffff67e3b77 →  mov rax, QWORD PTR [rbp-0x48]
$r8 : 0x3 
$r9 : 0x2 
$r10 : 0x7fffffffa1d8 → 0x00007ffff7fa8000 → 0x00007ffff7fde000 → 0x00007ffff716a698 → 0x00007ffff6f09090 → repz ret
$r11 : 0x7fffffffa1d8 → 0x00007ffff7fa8000 → 0x00007ffff7fde000 → 0x00007ffff716a698 → 0x00007ffff6f09090 → repz ret
$r12 : 0xffffffff55a → 0x0000000000000000
$r13 : 0x7fffffffaad0 → 0x0000000041b58ab3
$r14 : 0x6060000019a0 → 0x0000608000002120 → 0x00007ffff6d150a8 → 0x00007ffff67e8d36 →  push rbp
$r15 : 0x3 
$eflags: [ZERO carry PARITY adjust sign trap INTERRUPT direction overflow resume virtualx86 identification]
$ss: 0x002b $gs: 0x0000 $fs: 0x0000 $es: 0x0000 $cs: 0x0033 $ds: 0x0000 
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────[ stack ]────
0x00007fffffffa9e0│+0x00: 0x00007fffffffaa30 → 0x00007fffffffac80 → 0x00007fffffffad40 → 0x00007fffffffad90 → 0x00007fffffffc380 → 0x00007fffffffc3c0 → 0x00007fffffffc420 ← $rsp
0x00007fffffffa9e8│+0x08: 0x00006060000019a0 → 0x0000608000002120 → 0x00007ffff6d150a8 → 0x00007ffff67e8d36 →  push rbp
0x00007fffffffa9f0│+0x10: 0x00007fffffffffff
0x00007fffffffa9f8│+0x18: 0x0e8cb3deecb26000
0x00007fffffffaa00│+0x20: 0x00000008ffffae50 → 0x0000000000000000
0x00007fffffffaa08│+0x28: 0x0e8cb3deecb26000
0x00007fffffffaa10│+0x30: 0x00000ffffffff55a → 0x0000000000000000
0x00007fffffffaa18│+0x38: 0x00007fffffffac50 → 0x00007fffffffac90 → 0x000000000000000a
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────[ code:i386:x86-64 ]────
0x7ffff67e3b68  sbb BYTE PTR [rcx-0x3076b73a], cl
0x7ffff67e3b6f  call 0x7ffff64e7dd0 
0x7ffff67e3b74  mov DWORD PTR [rbp-0x40], eax
→ 0x7ffff67e3b77  mov rax, QWORD PTR [rbp-0x48]
0x7ffff67e3b7b  add rax, 0x18
0x7ffff67e3b7f  mov rdx, rax
0x7ffff67e3b82  mov rax, rdx
0x7ffff67e3b85  shr rax, 0x3
0x7ffff67e3b89  add rax, 0x7fff8000
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────[ source:/home/aceteam/Desktop/packages/poppler-master/poppler/Stream.cc+499 ]────
494 if (unlikely(inputLine == nullptr)) {
495 return nullptr;
496 }
497 
498 int readChars = str->doGetChars(inputLineSize, inputLine);
// readChars=-0x1
→ 499 for ( ; readChars < inputLineSize; readChars++) inputLine[readChars] = EOF;
500 if (nBits == 1) {
501 unsigned char *p = inputLine;
502 for (int i = 0; i > 7) & 1);
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────[ threads ]────
[#0] Id 1, Name: "pdfimages", stopped, reason: BREAKPOINT
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────[ trace ]────
[#0] 0x7ffff67e3b77 → Name: ImageStream::getLine(this=0x6060000019a0)
[#1] 0x55555556334b → Name: ImageOutputDev::writeImageFile(this=0x60f000000040, writer=0x603000010b10, format=ImageOutputDev::imgRGB, ext=0x55555556b8c0 "ppm", str=0x608000002120, width=0xa, height=0xa, colorMap=0x7fffffffbe70)
[#2] 0x55555556593a → Name: ImageOutputDev::writeImage(this=0x60f000000040, state=0x618000002080, ref=0x0, str=0x608000002120, width=0xa, height=0xa, colorMap=0x7fffffffbe70, inlineImg=0x1)
[#3] 0x555555565b96 → Name: ImageOutputDev::drawImage(this=0x60f000000040, state=0x618000002080, ref=0x0, str=0x608000002120, width=0xa, height=0xa, colorMap=0x7fffffffbe70, interpolate=0x0, maskColors=0x0, inlineImg=0x1)
[#4] 0x7ffff6667e1c → Name: Gfx::doImage(this=0x612000000640, ref=0x0, str=0x608000002120, inlineImg=0x1)
[#5] 0x7ffff666b5fa → Name: Gfx::opBeginImage(this=0x612000000640, args=0x7fffffffc5e0, numArgs=0x0)
[#6] 0x7ffff6636a49 → Name: Gfx::execOp(this=0x612000000640, cmd=0x7fffffffc4e0, args=0x7fffffffc5e0, numArgs=0x0)
[#7] 0x7ffff6635b3f → Name: Gfx::go(this=0x612000000640, topLevel=0x0)
[#8] 0x7ffff6635591 → Name: Gfx::display(this=0x612000000640, obj=0x7fffffffd070, topLevel=0x0)
[#9] 0x7ffff666b09f → Name: Gfx::drawForm(this=0x612000000640, str=0x7fffffffd070, resDict=0x6080000019a0, matrix=0x7fffffffce70, bbox=0x7fffffffce30, transpGroup=0x1, softMask=0x0, blendingColorSpace=0x0, isolated=0x0, knockout=0x0, alpha=0x0, transferFunc=0x0, backdropColor=0x0)
────────────────────────────────────────────────────────

gef➤ p/d readChars 
$21 = -1
  
  
Proof of Concept

: pdfimages -f 1 -l 1 -opw testing -upw testing -j -p -q $POC output *This can be triggerd when compiled with CFLAGS=”-fsanitize=address -g -O0"

Timeline

Vendor Disclosure: 2019-2-25

Public Disclosure:2019-3-2

Credit

Discovered by ACE Team - Loginsoft

Explore Cybersecurity Platforms

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros.

Discover Lovi
Stay Ahead

Get the Latest Cybersecurity Insights

Security research, threat intelligence, vulnerability updates, product news, and expert insights, delivered directly to your inbox. Stay informed. Stay secure.