Lucene search

K
securityvulnsSecurityvulnsSECURITYVULNS:DOC:26019
HistoryMar 29, 2011 - 12:00 a.m.

TSSA-2011-01 xpdf : multiple vulnerabilities allow remote code execution

2011-03-2900:00:00
vulners.com
19

  •         xpdf : multiple vulnerabilities in t1lib                    *
    
  •          allow arbitrary remote code execution                      *
    

  • –[ Vulnerability Summary:

Date Published: 28/03/2011
Last Update: 28/03/2011
Advisory ID: TSSA-2011-01
CVE Name: CVE-2011-0764 (previously known as VU#376500)
Title: xpdf : multiple vulnerabilities in t1lib
Remotely Exploitable: Yes
Locally Exploitable: No
Impact: Arbitrary code execution
Advisory URL: http://www.toucan-system.com/advisories/tssa-2011-01.txt

  • –[ Introduction:

    Following 3 paragraphs taken from the vendors' documentation:

    Xpdf is an open source viewer for Portable Document Format (PDF)
    files. (These are also sometimes also called 'Acrobat' files, from
    the name of Adobe's PDF software.) The Xpdf project also includes a
    PDF text extractor, PDF-to-PostScript converter, and various other
    utilities.

    Xpdf runs under the X Window System on UNIX, VMS, and OS/2. The non-X
    components (pdftops, pdftotext, etc.) also run on Win32 systems and
    should run on pretty much any system with a decent C++ compiler.

    Xpdf is designed to be small and efficient. It can use Type 1 or
    TrueType fonts.

  • –[ Synopsis:

    The linux version of xpdf is linked against t1lib, which is vulnerable
    to multiple vulnerabilities including off by ones, integer overflows
    and heap corruptions. At least one of those is exploitable and allows
    arbitrary code to be executed on the target machine when opening a
    specially crafted pdf file.

  • –[ Vulnerabilities overview:

    When parsing specially crafted Type 1 fonts, the t1lib library
    is subject to several memory corruption vulnerabilities. We will
    exemplify only a few of them : t1lib being decomissioned by xpdf
    anyways, it will probably never get fixed.

[*] Invalid memory reads (off by few):

The following valgrind trace exemplifies an invalid read from
t1lib:

==24009== Invalid read of size 8
==24009==    at 0x406364A: ??? (in /usr/lib/libt1.so.5.1.2)
==24009==    by 0x4068A0D: ??? (in /usr/lib/libt1.so.5.1.2)
==24009==    by 0x4068BEC: ??? (in /usr/lib/libt1.so.5.1.2)
==24009==    by 0x4069052: Type1Char (in /usr/lib/libt1.so.5.1.2)
==24009==    by 0x40540F3: fontfcnB (in /usr/lib/libt1.so.5.1.2)
==24009==    by 0x4077DDC: T1_SetChar (in /usr/lib/libt1.so.5.1.2)
==24009==    by 0x407CE88: T1_AASetChar (in /usr/lib/libt1.so.5.1.2)
==24009==    by 0x810C95A: ??? (in /usr/bin/xpdf.bin)
==24009==    by 0x810BE1E: ??? (in /usr/bin/xpdf.bin)
==24009==    by 0x80FA588: ??? (in /usr/bin/xpdf.bin)
==24009==    by 0x80C729F: ??? (in /usr/bin/xpdf.bin)
==24009==    by 0x8063A91: ??? (in /usr/bin/xpdf.bin)
==24009==    by 0x806452E: ??? (in /usr/bin/xpdf.bin)
==24009==    by 0x806224C: ??? (in /usr/bin/xpdf.bin)
==24009==    by 0x8062589: ??? (in /usr/bin/xpdf.bin)
==24009==    by 0x80A690A: ??? (in /usr/bin/xpdf.bin)
==24009==    by 0x80AB754: ??? (in /usr/bin/xpdf.bin)
==24009==    by 0x80ACF46: ??? (in /usr/bin/xpdf.bin)
==24009==    by 0x80E23D6: ??? (in /usr/bin/xpdf.bin)
==24009==    by 0x80A7BB0: ??? (in /usr/bin/xpdf.bin)
==24009==    by 0x80EE5B9: ??? (in /usr/bin/xpdf.bin)
==24009==    by 0x80DEB0F: ??? (in /usr/bin/xpdf.bin)
==24009==    by 0x80F1B32: ??? (in /usr/bin/xpdf.bin)
==24009==    by 0x458DB55: (below main) (libc-start.c:220)

Note: This given vulnerability cannot execute arbitrary code :
it only allows a remote denial of service of the xpdf reader.

[*] Invalid memory writes:

In the same fashion, the following trace exemplifies an invalid
memory write, dur to a use after free():

==23165== Invalid write of size 2
==23165==    at 0x405606C: t1_Bresenham (in /usr/lib/libt1.so.5.1.2)
==23165==    by 0x405627E: t1_StepLine (in /usr/lib/libt1.so.5.1.2)
==23165==    by 0x405B6E5: t1_Interior (in /usr/lib/libt1.so.5.1.2)
==23165==    by 0x405441B: fontfcnB (in /usr/lib/libt1.so.5.1.2)
==23165==    by 0x4077DDC: T1_SetChar (in /usr/lib/libt1.so.5.1.2)
==23165==    by 0x407CE88: T1_AASetChar (in /usr/lib/libt1.so.5.1.2)
==23165==    by 0x810C95A: ??? (in /usr/bin/xpdf.bin)
==23165==    by 0x810BE1E: ??? (in /usr/bin/xpdf.bin)
==23165==    by 0x80FA588: ??? (in /usr/bin/xpdf.bin)
==23165==    by 0x80C729F: ??? (in /usr/bin/xpdf.bin)
==23165==    by 0x8063A91: ??? (in /usr/bin/xpdf.bin)
==23165==    by 0x806452E: ??? (in /usr/bin/xpdf.bin)
==23165==    by 0x806224C: ??? (in /usr/bin/xpdf.bin)
==23165==    by 0x8062589: ??? (in /usr/bin/xpdf.bin)
==23165==    by 0x80A690A: ??? (in /usr/bin/xpdf.bin)
==23165==    by 0x80AB754: ??? (in /usr/bin/xpdf.bin)
==23165==    by 0x80ACF46: ??? (in /usr/bin/xpdf.bin)
==23165==    by 0x80E23D6: ??? (in /usr/bin/xpdf.bin)
==23165==    by 0x80A7BB0: ??? (in /usr/bin/xpdf.bin)
==23165==    by 0x80EE5B9: ??? (in /usr/bin/xpdf.bin)
==23165==    by 0x80DEB0F: ??? (in /usr/bin/xpdf.bin)
==23165==    by 0x80F1B32: ??? (in /usr/bin/xpdf.bin)
==23165==    by 0x458DB55: (below main) (libc-start.c:220)
==23165==  Address 0x4b7c978 is 19,560 bytes inside a block of size

26,624 free'd
==23165== at 0x4024886: free (vg_replace_malloc.c:325)
==23165== by 0x4069226: Type1Char (in /usr/lib/libt1.so.5.1.2)
==23165== by 0x40540F3: fontfcnB (in /usr/lib/libt1.so.5.1.2)
==23165== by 0x4077DDC: T1_SetChar (in /usr/lib/libt1.so.5.1.2)
==23165== by 0x407CE88: T1_AASetChar (in /usr/lib/libt1.so.5.1.2)
==23165== by 0x810C95A: ??? (in /usr/bin/xpdf.bin)
==23165== by 0x810BE1E: ??? (in /usr/bin/xpdf.bin)
==23165== by 0x80FA588: ??? (in /usr/bin/xpdf.bin)
==23165== by 0x80C729F: ??? (in /usr/bin/xpdf.bin)
==23165== by 0x8063A91: ??? (in /usr/bin/xpdf.bin)
==23165== by 0x806452E: ??? (in /usr/bin/xpdf.bin)
==23165== by 0x806224C: ??? (in /usr/bin/xpdf.bin)
==23165== by 0x8062589: ??? (in /usr/bin/xpdf.bin)
==23165== by 0x80A690A: ??? (in /usr/bin/xpdf.bin)
==23165== by 0x80AB754: ??? (in /usr/bin/xpdf.bin)
==23165== by 0x80ACF46: ??? (in /usr/bin/xpdf.bin)
==23165== by 0x80E23D6: ??? (in /usr/bin/xpdf.bin)
==23165== by 0x80A7BB0: ??? (in /usr/bin/xpdf.bin)
==23165== by 0x80EE5B9: ??? (in /usr/bin/xpdf.bin)
==23165== by 0x80DEB0F: ??? (in /usr/bin/xpdf.bin)
==23165== by 0x80F1B32: ??? (in /usr/bin/xpdf.bin)
==23165== by 0x458DB55: (below main) (libc-start.c:220)

Note: This given vulnerability cannot execute arbitrary code :
it only allows a remote denial of service of the xpdf reader.

[*] Off by one leading to invalid memory read, then integer overflow:

A more interresting case arrises in the following trace, for which
the pointer being dereferenced suggests the presence of an integer
overflow:

==24080== Invalid read of size 8
==24080==    at 0x4063409: ??? (in /usr/lib/libt1.so.5.1.2)
==24080==    by 0x40686A5: ??? (in /usr/lib/libt1.so.5.1.2)
==24080==    by 0x4068BEC: ??? (in /usr/lib/libt1.so.5.1.2)
==24080==    by 0x4069052: Type1Char (in /usr/lib/libt1.so.5.1.2)
==24080==    by 0x40540F3: fontfcnB (in /usr/lib/libt1.so.5.1.2)
==24080==    by 0x4077DDC: T1_SetChar (in /usr/lib/libt1.so.5.1.2)
==24080==    by 0x407CE88: T1_AASetChar (in /usr/lib/libt1.so.5.1.2)
==24080==    by 0x810C95A: ??? (in /usr/bin/xpdf.bin)
==24080==    by 0x810BE1E: ??? (in /usr/bin/xpdf.bin)
==24080==    by 0x80FA588: ??? (in /usr/bin/xpdf.bin)
==24080==    by 0x80C729F: ??? (in /usr/bin/xpdf.bin)
==24080==    by 0x8063A91: ??? (in /usr/bin/xpdf.bin)
==24080==    by 0x806452E: ??? (in /usr/bin/xpdf.bin)
==24080==    by 0x806224C: ??? (in /usr/bin/xpdf.bin)
==24080==    by 0x8062589: ??? (in /usr/bin/xpdf.bin)
==24080==    by 0x80A690A: ??? (in /usr/bin/xpdf.bin)
==24080==    by 0x80AB754: ??? (in /usr/bin/xpdf.bin)
==24080==    by 0x80ACF46: ??? (in /usr/bin/xpdf.bin)
==24080==    by 0x80E23D6: ??? (in /usr/bin/xpdf.bin)
==24080==    by 0x80A7BB0: ??? (in /usr/bin/xpdf.bin)
==24080==    by 0x80EE5B9: ??? (in /usr/bin/xpdf.bin)
==24080==    by 0x80DEB0F: ??? (in /usr/bin/xpdf.bin)
==24080==    by 0x80F1B32: ??? (in /usr/bin/xpdf.bin)
==24080==    by 0x458DB55: (below main) (libc-start.c:220)
==24080==  Address 0xffffff38 is not stack'd, malloc'd or (recently)

free'd

In fact, there is an off by one in t1lib responsible for the wrong

reading
of 4 null bytes from a mapped (t1lib's data) location at:
=> 0x4005f348: mov DWORD PTR [ebx+0x32b8],eax

Later on, this memory location is used to initialize eax with the value
of a (wrong) function pointer :
=> 0x4005f86a:  imul   eax,DWORD PTR [ebx+0x32b8],0x68
(at this point, eax will be NULL).

Then a fixed offset is substrated to eax (0 here), resulting in the

integer
overflow by wrap around:
=> 0x4005f885: sub eax,0xd0
(eax now worhes 0 - 0xd = 0xffffff30)

This pointer is finally used in floating point arithmetic to read a

pointer
into the FPU stack from an unmapped location, resulting in an
unvalid pointer
dereference and in fine in a segmentation fault:

Program received signal SIGSEGV, Segmentation fault.
  • -------------------------------------------------------------------------[
    regs]
    eax:FFFFFF30 ebx:40085FF4 ecx:0000658C edx:000000BB
    eflags:00010286
    esi:00000008 edi:00000002 esp:BFFFEA40 ebp:BFFFEAB8
    eip:4005F89A
    cs:0073 ds:007B es:007B fs:0000 gs:0033 ss:007B o d I t
    S z a P c

[0073:4005F89A]---------------------------------------------------------[ code]
–[ Instruction:
=> 0x4005f89a: fld QWORD PTR [eax+0x8]

Note: this vulnerability results in a Denial of Service but cannot

be used
to execute arbitrary code on the target.

[*] Arbitrary code execution:

In the following case, register ecx is user controled and allows
direct modification of the control flow:

gdb $ r ./testz.2184122398.pdf
Error (817488): Dictionary key must be a name object
Error (817492): Dictionary key must be a name object
Error (37300): Unknown operator 'lc'
Error (37385): Unknown operator 'lh'
Error (37504): Too few (5) args to 'c' operator
Error (37514): Too few (5) args to 'c' operator
Error (37543): Too few (5) args to 'c' operator
Error (37550): Unknown operator 'mh'
Error (37586): Too few (5) args to 'c' operator
Error (37603): Too few (5) args to 'c' operator
Error (37633): Too few (5) args to 'c' operator
Error (37669): Too few (5) args to 'c' operator
Error (37701): Too few (5) args to 'c' operator
Error (37733): Too few (5) args to 'c' operator
Error (37830): Too few (5) args to 'c' operator
Error (37839): Too few (5) args to 'cm' operator

Program received signal SIGSEGV, Segmentation fault.
  • -------------------------------------------------------------------------[
    regs]
    eax:08234138 ebx:00000000 ecx:AA55AA54 edx:00000054
    eflags:00010246
    esi:081CB298 edi:0821F2F0 esp:BFFFEF30 ebp:BFFFEFB8
    eip:080C512B
    cs:0073 ds:007B es:007B fs:0000 gs:0033 ss:007B o d I t
    s Z a P c

[0073:080C512B]---------------------------------------------------------[ code]
–[ Instruction:
=> 0x80c512b: call DWORD PTR [ecx+0x28]

By having ecx point 0x28 bytes to a location in the heap and

dereferencing a
pointer to this very same location, an attacker can execute
arbitrary shellcode,
hence performing arbitrary remote code execution on the target
machine uppon
opening of a given pdf file.

Reliability considerations: this particular bug is dependant on an

invalid
pointer dereferencing null data from a valid memory region. In order for
this to be performed without resulting in a segmentation fault, the
t1lib
library must read from a region wich is actually mapped, which
empirically
occures with a probability of around 10% of the cases on a machine
with ASLR
enabled.

  • –[ Mitigation:

    Instead of fixing the Type 1 library, the xpdf team has decided to
    end support for this library and encourages to link xpdf against the
    truetype library only. Versions starting with 3.02pl6 will therefor
    deprecate the use of t1lib completely.

    When compiling older versions manually, the CERT offers the following
    compilation options, which mitigate the vulnerability by not linking
    xpdf against the Type 1 library:

    To build Xpdf without t1lib, add the "–with-t1-library=no" flag to the
    configure command:

    ./configure --with-t1-library=no …

    To double-check, run "xpdf --help". The "-freetype" option should be
    listed, and the "-t1lib" option should NOT be listed. That indicates
    that Xpdf was built with FreeType and without t1lib.

    With this setting, Xpdf will use FreeType instead of t1lib to rasterize
    Type 1 fonts. With recent versions of FreeType, the Type 1 quality is
    as good or better than t1lib, so this should not present any problems.

  • –[ Vulnerable versions:

    Vulnerable : Xpdf up to (including) version 3.02pl5.
    Non vulnerable (non linked to t1lib) : Xpdf version 3.02pl6.

  • –[ Disclosure timeline:

    • 05/01/2011: Contact Vendor and CERT, providing full description
      and PoC samples to audit the issue.

    • 21/03/2011: The vendor releases a new version of the xpdf package,
      decomissioning the t1lib entirely, hence mitigating the problem.
      The CERT publishes a vulnerability note at the url:
      http://www.kb.cert.org/vuls/id/376500

    • 24/03/2011: The CERT assigns CVE number CVE-2011-0764 to this
      vulnerability.

    • 28/03/2011: Public disclosure.

  • –[ Credits:

    Those vulnerabilities were discovered by Jonathan Brossard from
    Toucan System.

  • –[ About Toucan System:

    Toucan System is a French computer security company providing
    cutting edge
    research and security consulting to Fortune 500 as well as smaller companies
    globally, thanks to a wide range of expertise ranging from Reverse
    Engineering
    and binary analysis to cryptography and Risk Management.