MOAB 6: PDF Reader Vulnerability

35 views
Skip to first unread message

Landon Fuller

unread,
Jan 6, 2007, 7:32:50 PM1/6/07
to moab...@googlegroups.com
http://projects.info-pull.com/moab/MOAB-06-01-2007.html

This one is tricky, and there are a number of vectors; mdimport will
automatically attempt to parse and index PDFs, for instance.

-landonf

PGP.sig

missileboat

unread,
Jan 6, 2007, 8:10:18 PM1/6/07
to MOAB Fixes
Ok, so, aside from having to Force Quit apps affected by a malicious
PDF, what else will this cause?

Steven

Matt Beaumont

unread,
Jan 6, 2007, 8:17:48 PM1/6/07
to moab...@googlegroups.com
On Sat, Jan 06, 2007 at 17:10:18 -0800, missileboat wrote:
> Ok, so, aside from having to Force Quit apps affected by a malicious
> PDF, what else will this cause?

Read the advisory carefully. The next step after memory corruption is
often execution of arbitrary code.

-Matt

Rosyna

unread,
Jan 6, 2007, 8:19:00 PM1/6/07
to moab...@googlegroups.com, Landon Fuller
So far, it seems like it is just an infinite loop of
CGPDFReaderGetPageDictionary(). mdimport automatically kills itself
after spending too much time on it. Safari just sits there eating
CPU. For the latter it's just a classic denial of service attack.

It also seems mdimport runs in the current user's context.

No need to worry about Acrobat Reader, since the issue has already
been fixed in version 8. That, and I venture to say that most mac
users don't use Adobe Acrobat reader to read PDFs. It's just too dang
slow and not fat.

I don't think this one is exploitable (even in theory) in the
CGPDFReaderGetPageDictionary() case. One method is to put some kinda
of static var in there that counts the number of times
CGPDFDictionaryGetCount() is called with the same object and the same
key (type). If you then return 0 from is_page_tree_node(), then the
PDF reader will correctly log: "Some pages of this PDF are corrupt
and will be ignored." Then all is well with the world.

--


Sincerely,
Rosyna Keller
Technical Support/Carbon troll/Always needs a hug

Unsanity: Unsane Tools for Insanely Great People

It's either this, or imagining Phil Schiller in a thong.

Rosyna

unread,
Jan 6, 2007, 8:23:26 PM1/6/07
to moab...@googlegroups.com, Matt Beaumont
I don't see any memory corruption in the CGPDFDocument case. Or any
exploitation condition on Mac OS X. Sadly, I don't have Adobe Reader
7.x or lower installed to see how it handles it.

The advisory seems to only state that Linux implementations crash.

--

Landon Fuller

unread,
Jan 6, 2007, 10:38:49 PM1/6/07
to moab...@googlegroups.com

On Jan 6, 2007, at 5:19 PM, Rosyna wrote:

> So far, it seems like it is just an infinite loop of
> CGPDFReaderGetPageDictionary(). mdimport automatically kills itself
> after spending too much time on it. Safari just sits there eating
> CPU. For the latter it's just a classic denial of service attack.
>
> It also seems mdimport runs in the current user's context.
>
> No need to worry about Acrobat Reader, since the issue has already
> been fixed in version 8. That, and I venture to say that most mac
> users don't use Adobe Acrobat reader to read PDFs. It's just too
> dang slow and not fat.
>
> I don't think this one is exploitable (even in theory) in the
> CGPDFReaderGetPageDictionary() case. One method is to put some
> kinda of static var in there that counts the number of times
> CGPDFDictionaryGetCount() is called with the same object and the
> same key (type). If you then return 0 from is_page_tree_node(),
> then the PDF reader will correctly log: "Some pages of this PDF are
> corrupt and will be ignored." Then all is well with the world.

In this particular case, the page node is self-referential -- from my
reproduction:
7 0 obj
<< /Type /Pages /MediaBox [0 0 612 792] /Count 1 /Kids [ 7 0 R ] >>
endobj

I've briefly played around with other potential error conditions, and
haven't been able to trigger any other bugs in CG's PDF handler --
not that my search was exhaustive.

-landonf

mart...@gmail.com

unread,
Jan 7, 2007, 4:36:14 AM1/7/07
to MOAB Fixes

On Jan 7, 2:17 am, Matt Beaumont <m...@cs.ucla.edu> wrote:
> On Sat, Jan 06, 2007 at 17:10:18 -0800, missileboat wrote:
> > Ok, so, aside from having to Force Quit apps affected by a malicious

> > PDF, what else will this cause?Read the advisory carefully. The next step after memory corruption is


> often execution of arbitrary code.
>
> -Matt

not often, rarely.

this is not a MOAB, this is a MOB.

there are thousands of bugs like this.

the next one will be:

when i modify the code of application X it crashes !

Landon Fuller

unread,
Jan 7, 2007, 8:41:48 PM1/7/07
to moab...@googlegroups.com

On Jan 6, 2007, at 7:38 PM, Landon Fuller wrote:

> In this particular case, the page node is self-referential -- from
> my reproduction:
> 7 0 obj
> << /Type /Pages /MediaBox [0 0 612 792] /Count 1 /Kids [ 7 0 R ] >>
> endobj

Attached is a patch against trunk that implements PDF loop detection.
I kept banging on this one late into the night just because the Proof-
of-Concept DoS is such a pain in the neck -- *everything* renders
PDFs, from Safari to Mail.app.

The bug itself is in the CGPDFReaderGetPageDictionary() function --
it doesn't implement any loop detection, such that a self-referential
PDF page node object can refer back to itself infinitely.
The fix works by maintaining a per-thread key for the length of the
CGPDFReaderGetPageDictionary() call. A counter is assigned to the key
upon entry to CGPDFReaderGetPageDictionary(), and the key is cleared
upon exit from CGPDFReaderGetPageDictionary().

pdf_xref_resolve() is called within the loop, and I use our
guard_pdf_xref_resolve() to acquire a reference to the pthread key
and increment the counter. When the counter hits MAX_LOOP (500000),
guard_pdf_xref_resolve() returns NULL, which the caller
(CGPDFReaderGetPageDictionary ) then handles correctly, breaking out
of the loop.

I'd appreciate a code review, and more sets of eyes on
CGPDFReaderGetPageDictionary and pdf_xref_resolve, to make sure I
didn't bungle anything. You can find my proof-of-concept PDF here:
http://landonf.bikemonkey.org/static/moab-tests/autopdf.html

Thanks,
landonf

pdfloop.diff
PGP.sig

Landon Fuller

unread,
Jan 7, 2007, 8:44:36 PM1/7/07
to moab...@googlegroups.com

On Jan 7, 2007, at 5:41 PM, Landon Fuller wrote:

> pdf_xref_resolve() is called within the loop, and I use our
> guard_pdf_xref_resolve() to acquire a reference to the pthread key
> and increment the counter. When the counter hits MAX_LOOP (500000),
> guard_pdf_xref_resolve() returns NULL, which the caller
> (CGPDFReaderGetPageDictionary ) then handles correctly, breaking
> out of the loop.

I should also note that the guard_pdf_xref_resolve() function skips
all loop detection if the pthread key is not set (ie, it is called
outside of CGPDFReaderGetPageDictionary())

-landonf

PGP.sig
Reply all
Reply to author
Forward
0 new messages