CVE-2018-19532: Null pointer dereference vulnerability in PdfTranslator::setTarget() – podofo 0.9.6

CVE-2018-19532: Null pointer dereference vulnerability in PdfTranslator::setTarget() – podofo 0.9.6

Loginsoft-2018-1034

November 15, 2018

CVE Number

CVE-2018-19532

CWE

CWE-476: NULL Pointer Dereference

Product Details

PoDoFo is a library to work with the PDF file format.
URL: https://sourceforge.net/projects/podofo/

Vulnerable Versions

0.9.6-trunk r1949

Vulnerability Details

During our research on the podofo, a NULL pointer dereference vulnerability is discovered in the pdofo (0.9.6 – Trunk r1949) .The same is triggered by sending a crafted pdf file to the podofoimpose binary.It allows an attacker to cause Denial of Service (Segmentation fault) or possibly have an unspecified other impact.

SYNOPSIS

As per our research,the vulnerability exits in function PdfTranslator::setTarget()in pdftranslator.cpp.
The pointer page,consists of pdf page details in it.

Gdb : 
gef➤  p page 
$53 = (PoDoFo::PdfPage *) 0x82a2d30 
gef➤  p *page 
$56 = { 
   = { 
    _vptr.PdfElement = 0x822b4c0, 
    m_pObject = 0x82a5f78 
  }, 
   = { 
    _vptr.PdfCanvas = 0x822b504  
  }, 
  members of PoDoFo::PdfPage: 
  m_pContents = 0x82a7870, 
  m_pResources = 0x82a8870, 
  m_mapAnnotations = std::map with 0 elements, 
  m_mapAnnotationsDirect = std::map with 0 elements

In line PdfXObject *xobj = new PdfXObject (page->GetMediaBox(), targetDoc),while storing the pdf objects in xobj,if a crafted pdf file is supplied to the binary,a NULL dereference issue is identified as the page pointer points to a non-existing address 0x0 .

Analysis
Source code :
for (int i = 0; i GetPage ( i );  
PdfMemoryOutputStream outMemStream ( 1 );  
PdfXObject *xobj = new PdfXObject ( page->GetMediaBox(), targetDoc );  
if ( page->GetContents()->HasStream() )  
{  
page->GetContents()->GetStream()->GetFilteredCopy ( &outMemStream );  
}

GDB : 
 
259                                     PdfXObject *xobj = new PdfXObject ( page->GetMediaBox(), targetDoc ); 
1: page = (PoDoFo::PdfPage *) 0x0 
[ Legend: Modified register | Code | Heap | Stack | String ] 
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ──── 
$eax   : 0x0 
$ebx   : 0x082a9de4  →  0x082aa7f0  →  0x08219b78  →  0x0813d594  →   push ebp 
$ecx   : 0x3 
$edx   : 0x082aaef0  →  0x00000000 
$esp   : 0xbffff470  →  0xb7bab000  →  0x00172664 
$ebp   : 0xbffff528  →  0xbffff568  →  0x00000000 
$esi   : 0xbffff4d8  →  0x00000000 
$edi   : 0xb7a16000  →  0x001b1db0 
$eip   : 0x0811bd62  →  <PoDoFo::Impose::PdfTranslator::setTarget(std::__cxx11::basic_string mov eax, DWORD PTR [ebp-0x90] 
$eflags: [carry parity adjust zero SIGN trap INTERRUPT direction overflow resume virtualx86 IDENTIFICATION] 
$cs: 0x0073 $ss: 0x007b $ds: 0x007b $es: 0x007b $fs: 0x0000 $gs: 0x0033 
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ──── 
0xbffff470│+0x0000: 0xb7bab000  →  0x00172664    ← $esp 
0xbffff474│+0x0004: 0xb7b08756  →  <__gnu_cxx::stdio_sync_filebuf add ebx, 0xa28aa 
0xbffff478│+0x0008: 0x08293b30  →  0x08293b38  →  "test" 
0xbffff47c│+0x000c: 0x082a1c48  →  0x082a1e10  →  0x0822aa54  →  0x081727a6  →   push ebp 
0xbffff480│+0x0010: 0x08293a40  →  0xb7ba9c68  →  0xb7b2d9e0  →  <std::basic_ostream push ebx 
0xbffff484│+0x0014: 0x082a9348  →  0x00000020 
0xbffff488│+0x0018: 0x00000001 
0xbffff48c│+0x001c: 0x00000001 
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:32 ──── 
    0x811bd59 <PoDoFo::Impose::PdfTranslator::setTarget(std::__cxx11::basic_string push   eax 
    0x811bd5a <PoDoFo::Impose::PdfTranslator::setTarget(std::__cxx11::basic_string call   0x813fa66  
    0x811bd5f <PoDoFo::Impose::PdfTranslator::setTarget(std::__cxx11::basic_string add    esp, 0x10 
→  0x811bd62 <PoDoFo::Impose::PdfTranslator::setTarget(std::__cxx11::basic_string mov    eax, DWORD PTR [ebp-0x90] 
    0x811bd68 <PoDoFo::Impose::PdfTranslator::setTarget(std::__cxx11::basic_string mov    eax, DWORD PTR [eax] 
    0x811bd6a <PoDoFo::Impose::PdfTranslator::setTarget(std::__cxx11::basic_string add    eax, 0x18 
    0x811bd6d <PoDoFo::Impose::PdfTranslator::setTarget(std::__cxx11::basic_string mov    eax, DWORD PTR [eax] 
    0x811bd6f <PoDoFo::Impose::PdfTranslator::setTarget(std::__cxx11::basic_string lea    edx, [ebp-0x50] 
    0x811bd72 <PoDoFo::Impose::PdfTranslator::setTarget(std::__cxx11::basic_string sub    esp, 0x8 
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────── source:/home/loginsoft/podofo-code-r1949-podofo-trunk/tools/podofoimpose/pdftranslator.cpp+259 ──── 
    254                         for ( int i = 0; i GetPage ( i ); 
    257                                 PdfMemoryOutputStream outMemStream ( 1 ); 
    258 
                // page=0xbffff498  →  0x00000000, xobj=0xbffff49c  →  [...]  →   push ebp 
→  259                                 PdfXObject *xobj = new PdfXObject ( page->GetMediaBox(), targetDoc ); 
    260                                 if ( page->GetContents()->HasStream() ) 
    261                                 { 
    262                                         page->GetContents()->GetStream()->GetFilteredCopy ( &outMemStream ); 
    263                                 } 
    264                                 else if ( page->GetContents()->IsArray() ) 
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ──── 
[#0] Id 1, Name: "podofoimpose", stopped, reason: BREAKPOINT 
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ──── 
[#0] 0x811bd62 → PoDoFo::Impose::PdfTranslator::setTarget(this=0x82a1c48, target="test") 
[#1] 0x8119af1 → main(argc=0x4, argv=0xbffff614) 
 
gef➤  p page 
$58 = (PoDoFo::PdfPage *) 0x0 
gef➤  p *page 
Cannot access memory at address 0x0 
gef➤  i r 
eax            0x0      0x0 
ecx            0x3      0x3 
edx            0x82aaef0        0x82aaef0 
ebx            0x82a9de4        0x82a9de4 
esp            0xbffff470       0xbffff470 
ebp            0xbffff528       0xbffff528 
esi            0xbffff4d8       0xbffff4d8 
edi            0xb7a16000       0xb7a16000 
eip            0x811bd62        0x811bd62 <PoDoFo::Impose::PdfTranslator::setTarget(std::__cxx11::basic_string<char, std::char_traits, std::allocator > const&)+320> 
eflags         0x200282 [ SF IF ID ] 
cs             0x73     0x73 
ss             0x7b     0x7b 
ds             0x7b     0x7b 
es             0x7b     0x7b 
fs             0x0      0x0 
gs             0x33     0x33 

gef➤  bt
#0  0x0811bd68 in PoDoFo::Impose::PdfTranslator::setTarget (this=0x82a1c70, target="test.pdf") at /home/loginsoft/podofo-code-r1949-podofo-trunk/tools/podofoimpose/pdftranslator.cpp:259
#1  0x08119af1 in main (argc=0x4, argv=0xbffff604) at /home/loginsoft/podofo-code-r1949-podofo-trunk/tools/podofoimpose/podofoimpose.cpp:108
Proof of Concept

podofoimpose $POC outfile.pdf native

Timeline

Vendor Disclosure: 2018-11-15
Public Disclosure: 2018-11-20
Patch : https://sourceforge.net/p/podofo/code/1950

Credit

Discovered by ACE Team – Loginsoft