What is the vulnerability?
A NULL pointer dereference vulnrability is discovered in the pdofo (0.9.6 - Trunk r1949 ) . The same be 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 unspecified other impact.
Version - 0.9.6 -Trunk r1949
Tested environment - 32-bit ubuntu 16.04 LTS
Command - podofoimpose $POC test.pdf native
vulnerable code
for (int i = 0; i < pcount ; ++i )
{
PdfPage * page = sourceDoc->GetPage ( i );
PdfMemoryOutputStream outMemStream ( 1 );
PdfXObject *xobj = new PdfXObject ( page->GetMediaBox(), targetDoc );
if ( page->GetContents()->HasStream() )
{
page->GetContents()->GetStream()->GetFilteredCopy ( &outMemStream );
}
Synopsis
As per our research, the vulnerability exits in functionPdfTranslator::setTarget in pdftranslator.cpp. The pointer page, contains the details of a pdf page.
Gdb :
gef➤ p page
$53 = (PoDoFo::PdfPage *) 0x82a2d30
gef➤ p *page
$56 = {
<PoDoFo::PdfElement> = {
_vptr.PdfElement = 0x822b4c0 <vtable for PoDoFo::PdfPage+8>,
m_pObject = 0x82a5f78
},
<PoDoFo::PdfCanvas> = {
_vptr.PdfCanvas = 0x822b504 <vtable for PoDoFo::PdfPage+76>
},
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 created as the page pointer points to an non-existing address 0x0 .
DEBUG
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 → <PoDoFo::PdfObject::~PdfObject()+0> 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<char,+0> 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<char,+0> add ebx, 0xa28aa 0xbffff478│+0x0008: 0x08293b30 → 0x08293b38 → "test" 0xbffff47c│+0x000c: 0x082a1c48 → 0x082a1e10 → 0x0822aa54 → 0x081727a6 → <PoDoFo::PdfMemDocument::~PdfMemDocument()+0> push ebp 0xbffff480│+0x0010: 0x08293a40 → 0xb7ba9c68 → 0xb7b2d9e0 → <std::basic_ostream<char,+0> push ebx 0xbffff484│+0x0014: 0x082a9348 → 0x00000020 0xbffff488│+0x0018: 0x00000001 0xbffff48c│+0x001c: 0x00000001 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:32 ──── 0x811bd59 <PoDoFo::Impose::PdfTranslator::setTarget(std::__cxx11::basic_string<char,+0> push eax 0x811bd5a <PoDoFo::Impose::PdfTranslator::setTarget(std::__cxx11::basic_string<char,+0> call 0x813fa66 <PoDoFo::PdfMemoryOutputStream::PdfMemoryOutputStream(int)> 0x811bd5f <PoDoFo::Impose::PdfTranslator::setTarget(std::__cxx11::basic_string<char,+0> add esp, 0x10 → 0x811bd62 <PoDoFo::Impose::PdfTranslator::setTarget(std::__cxx11::basic_string<char,+0> mov eax, DWORD PTR [ebp-0x90] 0x811bd68 <PoDoFo::Impose::PdfTranslator::setTarget(std::__cxx11::basic_string<char,+0> mov eax, DWORD PTR [eax] 0x811bd6a <PoDoFo::Impose::PdfTranslator::setTarget(std::__cxx11::basic_string<char,+0> add eax, 0x18 0x811bd6d <PoDoFo::Impose::PdfTranslator::setTarget(std::__cxx11::basic_string<char,+0> mov eax, DWORD PTR [eax] 0x811bd6f <PoDoFo::Impose::PdfTranslator::setTarget(std::__cxx11::basic_string<char,+0> lea edx, [ebp-0x50] 0x811bd72 <PoDoFo::Impose::PdfTranslator::setTarget(std::__cxx11::basic_string<char,+0> sub esp, 0x8 ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────── source:/home/loginsoft/podofo-code-r1949-podofo-trunk/tools/podofoimpose/pdftranslator.cpp+259 ──── 254 for ( int i = 0; i < pcount ; ++i ) 255 { 256 PdfPage * page = sourceDoc->GetPage ( i ); 257 PdfMemoryOutputStream outMemStream ( 1 ); 258 // page=0xbffff498 → 0x00000000, xobj=0xbffff49c → [...] → <PoDoFo::PdfXObject::~PdfXObject()+0> 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<char>, std::allocator<char> > 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
As this is clearly a security issue, the label "security" (missing before) is added and I've set it as "pending" even though I haven't reproduced it yet (but will try shortly) because it's so clearly explained here.
Thanks for the detailed report. Per my test the change I committed to svn r1950 fixes this issue, so I'm closing it.
FTR, this was given CVE-2018-19532