---------------------------------------------------------------------------
*             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.

Reply via email to