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