Menu

#33 Null pointer dereference in crop_page() of tools/podofocrop/podofocrop.cpp

SVN TRUNK
closed
security (37)
2019-02-11
2018-11-19
Ace Team
No

What is the vulnerability?
Invalid Memory Access vulnerability is discovered in the pdofo (0.9.6 - Trunk r1952). The same can be triggered by sending a crafted pdf file to the podofocrop binary. It allows an attacker to cause Denial of Service (Segmentation fault) or possibly have unspecified other impact when a victim opens a specially crafted file.

Version - 0.9.6 -Trunk r1952
Tested environment - 32-bit ubuntu 16.04 LTS
Command - podofocrop $POC test.pdf

vulnerable code -

void crop_page( PdfPage* pPage, const PdfRect & rCropBox )  
{ 
    PdfVariant var; 
    /* 
    printf("%f %f %f %f\n", 
           rCropBox.GetLeft(), 
           rCropBox.GetBottom(), 
           rCropBox.GetWidth(), 
           rCropBox.GetHeight()); 
    */ 
    rCropBox.ToVariant( var ); 
    pPage->GetObject()->GetDictionary().AddKey( PdfName("MediaBox"), var ); 
} 

Synopsis -
As per our research, the vulnerability exits in function crop_page() in podofocrop.cpp. When the line pPage->GetObject()->GetDictionary().AddKey( PdfName("MediaBox"), var ); executes, it calls the function GetObject() located in PdfElement.h, which returns m_pObjects, located at location [DWORD ESP+0X4].

inline PdfObject* PdfElement::GetObject() 
{ 
    return m_pObject; 
}

Valid scenario -

Gdb: 
[ Legend: Modified register | Code | Heap | Stack | String ] 
────────────────────────────────────────────────────────────────────────────────────── registers ──── 
$eax   : 0xb4e00f10  →  0x081d4958  →  0x081342a0  →  <PoDoFo::PdfInfo::~PdfInfo()+0> push ebp 
$ebx   : 0xb4e00f10  →  0x081d4958  →  0x081342a0  →  <PoDoFo::PdfInfo::~PdfInfo()+0> push ebp 
$ecx   : 0x0 
$edx   : 0x7 
$esp   : 0xbffff188  →  0xbffff318  →  0xbffff338  →  0xbffff3d8  →  0xbffff418  →  0xbffff568  →  0x00000000 
$ebp   : 0xbffff188  →  0xbffff318  →  0xbffff338  →  0xbffff3d8  →  0xbffff418  →  0xbffff568  →  0x00000000 
$esi   : 0xb4403bc0  →  0x081dad68  →  0x08177cde  →  <PoDoFo::PdfParserObject::~PdfParserObject()+0> push ebp 
$edi   : 0xb74e8000  →  0x001b1db0 
$eip   : 0x080f7253  →  <PoDoFo::PdfElement::GetObject()+3> mov eax, DWORD PTR [ebp+0x8] 
$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 ──── 
0xbffff188│+0x0000: 0xbffff318  →  0xbffff338  →  0xbffff3d8  →  0xbffff418  →  0xbffff568  →  0x00000000        ← $esp, $ebp 
0xbffff18c│+0x0004: 0x08134434  →  <PoDoFo::PdfInfo::Init(int)+312> add esp, 0x10 
0xbffff190│+0x0008: 0xb4e00f10  →  0x081d4958  →  0x081342a0  →  <PoDoFo::PdfInfo::~PdfInfo()+0> push ebp 
0xbffff194│+0x000c: 0x081d48df  →  "ModDate" 
0xbffff198│+0x0010: 0x00000006 
0xbffff19c│+0x0014: 0x00000000 
0xbffff1a0│+0x0018: 0xb4601a50  →  0x081c2f94  →  0x080f7e9c  →  <PoDoFo::PdfDictionary::~PdfDictionary()+0> push ebp 
0xbffff1a4│+0x001c: 0x00000000 
─────────────────────────────────────────────────────────────────────────────────── code:x86:32 ──── 
    0x80f724f                  nop 
    0x80f7250 <PoDoFo::PdfElement::GetObject()+0> push   ebp 
    0x80f7251 <PoDoFo::PdfElement::GetObject()+1> mov    ebp, esp 
→  0x80f7253 <PoDoFo::PdfElement::GetObject()+3> mov    eax, DWORD PTR [ebp+0x8] 
    0x80f7256 <PoDoFo::PdfElement::GetObject()+6> mov    eax, DWORD PTR [eax+0x4] 
    0x80f7259 <PoDoFo::PdfElement::GetObject()+9> pop    ebp 
    0x80f725a <PoDoFo::PdfElement::GetObject()+10> ret 
    0x80f725b                  nop 
    0x80f725c <std::vector<PoDoFo::PdfRect,+0> push   ebp 
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── source:/home/loginsoft/podofo-code-r1952-podofo-trunk/src/doc/PdfElement.h+180 ──── 

    178  inline PdfObject* PdfElement::GetObject() 
    179  { 
→  180      return m_pObject; 
    181  } 

──────────────────────────────────────────────────────────────────────────────────────────────── threads ──── 
[#0] Id 1, Name: "podofocrop", stopped, reason: BREAKPOINT 
───────────────────────────────────────────────────────────────────────────────────────────── trace ──── 
[#0] 0x80f7253 → PoDoFo::PdfElement::GetObject(this=0xb4e00f10) 
[#1] 0x8134434 → PoDoFo::PdfInfo::Init(this=0xb4e00f10, eInitial=0x2) 
[#2] 0x8134279 → PoDoFo::PdfInfo::PdfInfo(this=0xb4e00f10, pObject=0xb4402a40, eInitial=0x2) 
[#3] 0x81357d9 → PoDoFo::PdfMemDocument::InitFromParser(this=0xbffff464, pParser=0xb4003e40) 
[#4] 0x8135b9d → PoDoFo::PdfMemDocument::Load(this=0xbffff464, pszFilename=0xbffff776 "crash1", bForUpdate=0x0) 
[#5] 0x80f6592 → main(argc=0x3, argv=0xbffff614) 
───────────────────────────────────────────────────────────────────────────── 
gef➤  p m_pObject 
$15 = (PoDoFo::PdfObject *) 0xb4402a40 
gef➤  p $eax+0x4 
$16 = 0xb4e00f14 
gef➤  x/8w $eax+0x4 
0xb4e00f14:     0xb4402a40      0x0     0x0     0x2 
0xb4e00f24:     0x4ffffff       0xc     0x30800002      0x81c4a60 

Vulnerable scenario -

When a crafted pdf is passed to the binary, it changes the return address m_pObjects of the function PdfElement::GetObject(), leading to an Invalid Memory Access vulnerability.

GDB : 
180         return m_pObject; 
[ Legend: Modified register | Code | Heap | Stack | String] 
────────────────────────────────────────────────────────────────────────────────────────────────────── registers ──── 
$eax   : 0x0 
$ebx   : 0x2 
$ecx   : 0x0 
$edx   : 0x8 
$esp   : 0xbffff388    0xbffff418    0xbffff568    0x00000000 
$ebp   : 0xbffff388    0xbffff418    0xbffff568    0x00000000 
$esi   : 0xb74e8000    0x001b1db0 
$edi   : 0xb74e8000    0x001b1db0 
$eip   : 0x080f7253    <PoDoFo::PdfElement::GetObject()+3> mov eax, DWORD PTR [ebp+0x8] 
$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 ──── 
0xbffff388+0x0000: 0xbffff418    0xbffff568    0x00000000      $esp, $ebp 
0xbffff38c+0x0004: 0x080f5e6b    <crop_page(PoDoFo::PdfPage*,+0> add esp, 0x10 
0xbffff390+0x0008: 0x00000000 
0xbffff394+0x000c: 0x081c281b    "MediaBox" 
0xbffff398+0x0010: 0x00000005 
0xbffff39c+0x0014: 0x00000000 
0xbffff3a0+0x0018: 0x00000000 
0xbffff3a4+0x001c: 0xb5a01420    0x2a000006    0x00000000 
────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:32 ──── 
    0x80f724f                  nop 
    0x80f7250 <PoDoFo::PdfElement::GetObject()+0> push   ebp 
    0x80f7251 <PoDoFo::PdfElement::GetObject()+1> mov    ebp, esp 
   0x80f7253 <PoDoFo::PdfElement::GetObject()+3> mov    eax, DWORD PTR [ebp+0x8] 
    0x80f7256 <PoDoFo::PdfElement::GetObject()+6> mov    eax, DWORD PTR [eax+0x4] 
    0x80f7259 <PoDoFo::PdfElement::GetObject()+9> pop    ebp 
    0x80f725a <PoDoFo::PdfElement::GetObject()+10> ret 
    0x80f725b                  nop 
    0x80f725c <std::vector<PoDoFo::PdfRect,+0> push   ebp 
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── source:/home/loginsoft/podofo-code-r1952-podofo-trunk/src/doc/PdfElement.h+180 ──── 

    178  inline PdfObject* PdfElement::GetObject() 
    179  { 
   180      return m_pObject; 
    181  } 
──────────────────────────────────────── threads ──── 
[#0] Id 1, Name: "podofocrop", stopped, reason: BREAKPOINT ─────────────────────────────────────────────────────────────────────────────── trace ──── 
[#0] 0x80f7253  PoDoFo::PdfElement::GetObject(this=0x0) 
[#1] 0x80f5e6b  crop_page(pPage=0x0, rCropBox=@0xb5001760) 
[#2] 0x80f66ba  main(argc=0x3, argv=0xbffff614) 
─────────────────────────────────────────────────────────────

gef  p m_pObject 
Cannot access memory at address 0x4 
gef  p $eax+0x4 
$19 = 0x4 
gef  x/w $eax+0x4 
0x4:    Cannot access memory at address 0x4 
1 Attachments
POC

Related

Tickets: #1
Tickets: #2
Tickets: #3
Tickets: #4
Tickets: #5

Discussion

  • Matthew Brincke

    Matthew Brincke - 2018-11-22
    • summary: Invalid Memory Access in PdfElement::GetObject() --> Null pointer dereference in crop_page() of tools/podofocrop/podofocrop.cpp
    • status: open --> pending
    • assigned_to: Matthew Brincke
     
  • Matthew Brincke

    Matthew Brincke - 2018-11-22

    The security vulnerability isn't in PdfElement::GetObject() because it can't be fixed there: calling a method from a nullptr object is undefined behaviour - nothing in the method can change that. Therefore, the usage of pPage in the function crop_page() of podofocrop.cpp needs a nullptr check.

     
    • Ace Team

      Ace Team - 2018-11-23

      Right! Now it makes sense. We tried to analyse what payload in the PDF causing this issue.
      Thanks for the clarification.

       
  • Matthew Brincke

    Matthew Brincke - 2018-11-26
    • status: pending --> closed
     
  • Matthew Brincke

    Matthew Brincke - 2018-11-26

    IMHO the fix for this is so simple that testing with GCC 4.9.2 is enough (sorry, I don't have a newer one handy these days), which I have done, so I'm closing here. Further independent corroboration (or showing flaws) is still welcomed though, including with differences in build configuration (mine isn't with full library support, and I've checked only the shared build, please speak up e.g. on the mailing list when you've got reasoning/evidence this isn't enough for this simple case).

     
    • Ace Team

      Ace Team - 2018-11-27

      We have tested in GCC version 5.5.0 and able to reproduce the issue by configuring full Library. I missed the point here, do you mean that we need to compile with older versions of GCC ?

      Curious to know, can't this issue be fixed by having a NULL check against 'pPage', which solves the issue though the user is using latest GCC version?

       
      • Matthew Brincke

        Matthew Brincke - 2018-11-27

        Did you use the latest revision of PoDoFo, i.e. svn r1954 which does contain the NULL check on pPage? I had hoped this issue isn't dependent on the compiler version (nor library configuration) ... I'll have to check with a newer GCC version (could be newer than 5.5.0 though, IIRC GCC 7, currently 7.3, is supported upstream and in the newest Ubuntu LTS, 18.04, section main).

         

        Last edit: Matthew Brincke 2018-11-27
  • Ace Team

    Ace Team - 2018-11-30

    We now confirm that the issue has been fixed in svn r1954.

     
  • Mattia Rizzolo

    Mattia Rizzolo - 2019-02-11

    FTR, this has been given CVE-2018-20751