[go: up one dir, main page]

Bug 2704 - There is a heap based buffer overflow in the tiff2pdf tool of the libtiff library. A crafted TIFF document can lead to a heap based buffer overflow resulting in multiple damages.
: There is a heap based buffer overflow in the tiff2pdf tool of the libtiff lib...
Status: RESOLVED FIXED
: libtiff
default
: unspecified
: All Linux
: P1 blocker
: ---
Assigned To:
:
:
:
:
:
  Show dependency treegraph
 
Reported: 2017-06-22 01:55 by
Modified: 2017-12-10 16:12 (History)


Attachments
the vulnerability is triggered by ./tiff2pdf $FILE (3.99 KB, application/octet-stream)
2017-06-22 01:55, owl337
Details
Patch to fix CVE-2017-9935. (4.09 KB, patch)
2017-12-06 01:18, Brian May
Details | Diff
Patch to fix transfer table type error (1.71 KB, patch)
2017-12-06 01:19, Brian May
Details | Diff


Note

You need to log in before you can comment on or make changes to this bug.


Description From 2017-06-22 01:55:38
Created an attachment (id=788) [details]
the vulnerability is triggered by ./tiff2pdf $FILE

The asan debug information is below:

==125927==ERROR: AddressSanitizer: heap-buffer-overflow on address
0x60b00000aff8 at pc 0x0000004174c4 bp 0x7ffcb6eb6160 sp 0x7ffcb6eb6150
WRITE of size 4 at 0x60b00000aff8 thread T0
Xshell    #0 0x4174c3 in t2p_write_pdf
/home/company/real/libtiff-master-latest/tools/tiff2pdf.c:5481
    #1 0x402151 in main
/home/company/real/libtiff-master-latest/tools/tiff2pdf.c:808
    #2 0x7f30f0d5fa3f in __libc_start_main
(/lib/x86_64-linux-gnu/libc.so.6+0x20a3f)
    #3 0x402e08 in _start
(/home/company/real/libtiff-master-latest/install_asan/bin/tiff2pdf+0x402e08)

0x60b00000aff8 is located 0 bytes to the right of 104-byte region
[0x60b00000af90,0x60b00000aff8)
allocated by thread T0 here:
    #0 0x7f30f149f9aa in malloc
(/usr/lib/x86_64-linux-gnu/libasan.so.2+0x989aa)
    #1 0x415f27 in t2p_write_pdf
/home/company/real/libtiff-master-latest/tools/tiff2pdf.c:5424

SUMMARY: AddressSanitizer: heap-buffer-overflow
/home/company/real/libtiff-master-latest/tools/tiff2pdf.c:5481 t2p_write_pdf
Shadow bytes around the buggy address:
  0x0c167fff95a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c167fff95b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c167fff95c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c167fff95d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c167fff95e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c167fff95f0: fa fa 00 00 00 00 00 00 00 00 00 00 00 00 00[fa]
  0x0c167fff9600: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c167fff9610: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c167fff9620: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c167fff9630: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c167fff9640: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
==125927==ABORTING



The function t2p_write_pdf(tiff2pdf.c:5424) allocated buffer
t2p->pdf_xrefoffsets of size t2p->pdf_xrefcount*sizeof(uint32).  The value of 
t2p->pdf_xrefcount is parsed from t2p_read_tiff_init(tiff2pdf.c:5422)at first,
and assigned to 0 in line 5433 . An illegal TIFF document could have a big
t2p->tiff_transferfunctioncount(tiff2pdf.c:5480) that cause  heap overflow with
operation t2p->pdf_xrefcount++. 

This heap overflow could lead to different damages. For example, a crafted TIFF
document can lead to out of bound read in TIFFCleanup (trigger by POC1 in the
attachment) , invalid free in TIFFClose (trigger by POC2 in attachment) or
t2p_free(trigger by POC3 in attachment) , memory corruption in
t2p_readwrite_pdf_image(trigger by POC4 in attachment), double free in
t2p_free(trigger by POC5 in attachment). Given these possibilities, it probably
could cause arbitrary code execution, although a more detail analysis of this
vulnerability is required.

5415 tsize_t t2p_write_pdf(T2P* t2p, TIFF* input, TIFF* output){
...
5422         t2p_read_tiff_init(t2p, input);
5423         if(t2p->t2p_error!=T2P_ERR_OK){return(0);}
5424         t2p->pdf_xrefoffsets= (uint32*)
_TIFFmalloc(TIFFSafeMultiply(tmsize_t,t2p->pdf_xrefcount,sizeof(uint32))
);//allocate
...
5432         }
5433         t2p->pdf_xrefcount=0;
...
5478                written += t2p_write_pdf_transfer(t2p, output);
5479                written += t2p_write_pdf_obj_end(output);
5480                for(i=0; i < t2p->tiff_transferfunctioncount; i++){
5481                   
t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;//heap overflow
5482                    written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount,
output);
...

The gdb debug information for these five POC samples are as followings.Each one
has different effects to the program.


$gdb  ./tiff2pdf

(gdb) set args POC1
(gdb) r
 ...
XshellProgram received signal SIGSEGV, Segmentation fault.
TIFFCleanup (tif=tif@entry=0x60fc10) at tif_close.c:85
85                if (fld->field_bit == FIELD_CUSTOM &&
(gdb) bt
#0  TIFFCleanup (tif=tif@entry=0x60fc10) at tif_close.c:85
#1  0x00007ffff7b77ba9 in TIFFClose (tif=tif@entry=0x60fc10) at tif_close.c:128
#2  0x00000000004019fb in main (argc=<optimized out>, argv=<optimized out>) at
tiff2pdf.c:820


(gdb) set args POC2
(gdb) r
 ...

Program received signal SIGABRT, Aborted.
0x00007ffff77da267 in __GI_raise (sig=sig@entry=6) at
../sysdeps/unix/sysv/linux/raise.c:55
55    ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0  0x00007ffff77da267 in __GI_raise (sig=sig@entry=6) at
../sysdeps/unix/sysv/linux/raise.c:55
#1  0x00007ffff77dbeca in __GI_abort () at abort.c:89
#2  0x00007ffff781dc53 in __libc_message (do_abort=do_abort@entry=1,
fmt=fmt@entry=0x7ffff79361a8 "*** Error in `%s': %s: 0x%s ***\n") at
../sysdeps/posix/libc_fatal.c:175
#3  0x00007ffff78299f8 in malloc_printerr (ptr=<optimized out>,
str=0x7ffff79361d0 "munmap_chunk(): invalid pointer", action=<optimized out>)
at malloc.c:4965
#4  munmap_chunk (p=<optimized out>) at malloc.c:2820
#5  __GI___libc_free (mem=<optimized out>) at malloc.c:2945
#6  0x00007ffff7b77b0c in TIFFCleanup (tif=tif@entry=0x60fc10) at
tif_close.c:87
#7  0x00007ffff7b77ba9 in TIFFClose (tif=tif@entry=0x60fc10) at tif_close.c:128
#8  0x00000000004019fb in main (argc=<optimized out>, argv=<optimized out>) at
tiff2pdf.c:820


(gdb) set args POC3
(gdb) r
...

Program received signal SIGABRT, Aborted.
0x00007ffff77da267 in __GI_raise (sig=sig@entry=6) at
../sysdeps/unix/sysv/linux/raise.c:55
55    ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0  0x00007ffff77da267 in __GI_raise (sig=sig@entry=6) at
../sysdeps/unix/sysv/linux/raise.c:55
#1  0x00007ffff77dbeca in __GI_abort () at abort.c:89
#2  0x00007ffff781dc53 in __libc_message (do_abort=do_abort@entry=1,
fmt=fmt@entry=0x7ffff79361a8 "*** Error in `%s': %s: 0x%s ***\n") at
../sysdeps/posix/libc_fatal.c:175
#3  0x00007ffff7825c69 in malloc_printerr (ptr=<optimized out>,
str=0x7ffff7936220 "free(): invalid next size (fast)", action=1) at
malloc.c:4965
#4  _int_free (av=<optimized out>, p=<optimized out>, have_lock=0) at
malloc.c:3834
#5  0x00007ffff782989c in __GI___libc_free (mem=<optimized out>) at
malloc.c:2950
#6  0x0000000000402a91 in t2p_free (t2p=t2p@entry=0x60f010) at tiff2pdf.c:969
#7  0x0000000000401c69 in main (argc=<optimized out>, argv=<optimized out>) at
tiff2pdf.c:824


(gdb) set args POC4
(gdb) r
 ...
Program received signal SIGABRT, Aborted.
0x00007ffff77da267 in __GI_raise (sig=sig@entry=6) at
../sysdeps/unix/sysv/linux/raise.c:55
55    ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0  0x00007ffff77da267 in __GI_raise (sig=sig@entry=6) at
../sysdeps/unix/sysv/linux/raise.c:55
#1  0x00007ffff77dbeca in __GI_abort () at abort.c:89
#2  0x00007ffff781dc53 in __libc_message (do_abort=1,
fmt=fmt@entry=0x7ffff79361a8 "*** Error in `%s': %s: 0x%s ***\n") at
../sysdeps/posix/libc_fatal.c:175
#3  0x00007ffff7826e5e in malloc_printerr (ptr=0x614bb0, str=0x7ffff793237b
"malloc(): memory corruption", action=<optimized out>) at malloc.c:4965
#4  _int_malloc (av=av@entry=0x7ffff7b69c00 <main_arena>,
bytes=bytes@entry=3342336) at malloc.c:3441
#5  0x00007ffff782950e in __GI___libc_malloc (bytes=3342336) at malloc.c:2895
#6  0x0000000000403be1 in t2p_readwrite_pdf_image (t2p=t2p@entry=0x60f010,
input=input@entry=0x60fc10, output=output@entry=0x610e60) at tiff2pdf.c:2445
#7  0x000000000040a410 in t2p_readwrite_pdf_image (output=0x610e60,
input=0x60fc10, t2p=0x60f010) at tiff2pdf.c:5480
#8  t2p_write_pdf (t2p=0x60f010, input=0x60fc10, output=0x610e60) at
tiff2pdf.c:5558
#9  0x00000000004019e8 in main (argc=<optimized out>, argv=<optimized out>) at
tiff2pdf.c:808

(gdb) set args POC5
(gdb) r


*** Error in `/home/company/real/libtiff-master-latest/install/bin/tiff2pdf':
double free or corruption (!prev): 0x0000000000613640 ***
Xshell
Program received signal SIGABRT, Aborted.
0x00007ffff77da267 in __GI_raise (sig=sig@entry=6) at
../sysdeps/unix/sysv/linux/raise.c:55
55    ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0  0x00007ffff77da267 in __GI_raise (sig=sig@entry=6) at
../sysdeps/unix/sysv/linux/raise.c:55
#1  0x00007ffff77dbeca in __GI_abort () at abort.c:89
#2  0x00007ffff781dc53 in __libc_message (do_abort=do_abort@entry=1,
fmt=fmt@entry=0x7ffff79361a8 "*** Error in `%s': %s: 0x%s ***\n") at
../sysdeps/posix/libc_fatal.c:175
#3  0x00007ffff7825c69 in malloc_printerr (ptr=<optimized out>,
str=0x7ffff79362d8 "double free or corruption (!prev)", action=1) at
malloc.c:4965
#4  _int_free (av=<optimized out>, p=<optimized out>, have_lock=0) at
malloc.c:3834
#5  0x00007ffff782989c in __GI___libc_free (mem=<optimized out>) at
malloc.c:2950
#6  0x0000000000402a91 in t2p_free (t2p=t2p@entry=0x60f010) at tiff2pdf.c:969
#7  0x0000000000401c69 in main (argc=<optimized out>, argv=<optimized out>) at
tiff2pdf.c:824

Affected version:
the Latest version (4.0.8)
4.0.7
…

Credits:

This vulnerability is detected by team OWL337, with our custom fuzzer collAFL.
Please contact ganshuitao@gmail.com  and chaoz@tsinghua.edu.cn if you need more
info about the team, the tool or the vulnerability.
------- Comment #1 From 2017-06-27 02:01:53 -------
CVE-2017-9935 has been assigned for this.
------- Comment #2 From 2017-06-27 02:31:11 -------
I'm unable to reproduce this issue with latest CVS version. Not sure which
commit fixed this issue, but I believe the CVE is now duplicate and should be
rejected. Could you retest against latest CVS?
------- Comment #3 From 2017-06-27 05:45:49 -------
(In reply to comment #2)
> I'm unable to reproduce this issue with latest CVS version. Not sure which
> commit fixed this issue, but I believe the CVE is now duplicate and should be
> rejected. Could you retest against latest CVS?
Yes, I have checked the latest CVS, all bugs in this vulnerability are
triggered as crash both of asan and non-asan mode. In addition, the heap
overflow is precise in t2p_write_pdf funtion as follows:
    #0 0x7fd56dcbf9aa in malloc
(/usr/lib/x86_64-linux-gnu/libasan.so.2+0x989aa)
    #1 0x415f17 in t2p_write_pdf
/home/company/real/libtiff/tools/tiff2pdf.c:5424

SUMMARY: AddressSanitizer: heap-buffer-overflow
/home/company/real/libtiff/tools/tiff2pdf.c:5481 t2p_write_pdf
Shadow bytes around the buggy address:
  0x0c167fff95a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c167fff95b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c167fff95c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c167fff95d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c167fff95e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c167fff95f0: fa fa 00 00 00 00 00 00 00 00 00 00 00 00 00[fa]
  0x0c167fff9600: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c167fff9610: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c167fff9620: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c167fff9630: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c167fff9640: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
------- Comment #4 From 2017-06-27 05:59:49 -------
As I described, it's sure a very serious unknown vulnerability and not easy to
repair.
------- Comment #5 From 2017-06-27 06:27:19 -------
Okay. Maybe there is something wrong with my own setup then. Which command did
you use to fetch the latest version? I also tried with unofficial
https://github.com/vadz/libtiff and no luck.
------- Comment #6 From 2017-06-27 06:32:27 -------
(In reply to comment #5)
> Okay. Maybe there is something wrong with my own setup then. Which command did
> you use to fetch the latest version? I also tried with unofficial
> https://github.com/vadz/libtiff and no luck.

company@ubuntu:~/real/libtiff$ export
CVSROOT=:pserver:cvsanon@cvs.maptools.org:/cvs/maptools/cvsroot
company@ubuntu:~/real/libtiff$ cvs login
(empty passwd)
company@ubuntu:~/real/libtiff$ cvs checkout libtiff
------- Comment #7 From 2017-06-27 06:35:12 -------
(In reply to comment #5)
> Okay. Maybe there is something wrong with my own setup then. Which command did
> you use to fetch the latest version? I also tried with unofficial
> https://github.com/vadz/libtiff and no luck.

It's sure the latest, the start of changlog is as follows:

2017-06-26  Even Rouault <even.rouault at spatialys.com>

        * libtiff/tif_jbig.c: fix memory leak in error code path of
JBIGDecode()
        Fixes http://bugzilla.maptools.org/show_bug.cgi?id=2706
        Reported by team OWL337

2017-06-24  Even Rouault <even.rouault at spatialys.com>

        * libtiff/tif_jpeg.c: error out at decoding time if anticipated libjpeg
        memory allocation is above 100 MB. libjpeg in case of multiple scans,
        which is allowed even in baseline JPEG, if components are spread over
several
        scans and not interleavedin a single one, needs to allocate memory (or
        backing store) for the whole strip/tile.
        See
http://www.libjpeg-turbo.org/pmwiki/uploads/About/TwoIssueswiththeJPEGStandard.pdf
        This limitation may be overriden by setting the
        LIBTIFF_ALLOW_LARGE_LIBJPEG_MEM_ALLOC environment variable, or
recompiling
        libtiff with a custom value of TIFF_LIBJPEG_LARGEST_MEM_ALLOC macro.
...
------- Comment #8 From 2017-06-27 13:56:36 -------
There is something wrong with my setup. Please ignore my recent comments. This
has been verified by Debian security team member. I'll investigate and get back
to you. Sorry for the noise.
------- Comment #9 From 2017-06-29 09:48:45 -------
(In reply to comment #8)
> There is something wrong with my setup. Please ignore my recent comments. This
> has been verified by Debian security team member. I'll investigate and get back
> to you. Sorry for the noise.

It doesn't matter. Debug need to be patient.
------- Comment #10 From 2017-06-29 09:49:04 -------
(In reply to comment #8)
> There is something wrong with my setup. Please ignore my recent comments. This
> has been verified by Debian security team member. I'll investigate and get back
> to you. Sorry for the noise.

It doesn't matter. Debug need to be patient.
------- Comment #11 From 2017-07-15 09:37:23 -------
Looks like it might be similar to
http://bugzilla.maptools.org/show_bug.cgi?id=2663 which also involves
TransferFunction
------- Comment #12 From 2017-08-23 07:22:39 -------
(In reply to comment #11)
> Looks like it might be similar to
> http://bugzilla.maptools.org/show_bug.cgi?id=2663 which also involves
> TransferFunction

Hello, I wanna know if your team fix this bug?
------- Comment #13 From 2017-08-23 07:34:32 -------
> Hello, I wanna know if your team fix this bug?

Be aware that libtiff is free software maintained mostly by volunteers in their
free time, and few of the current active maintainers have direct interest in
the utilities, but are more focused on the library itself. So if you're in
position to contribute a patch to fix the issue, please do so.
------- Comment #14 From 2017-11-15 01:16:06 -------
note the terminology: the tiff spec talks about a tiff file containing multiple
images; the tiff2pdf talks about pages instead; Here I will use the "image"
term to refer to multiple images in a single tiff file.

After studying this problem for a while, it appears that tiff2pdf assumes that
every image in a multiple image tiff file will use the same transfer function.

I don't see anywhere in the tiff specs that say this assumption is valid. Every
image is allowed to have a different transfer function. As in I don't think
there is anything wrong with the POC1 image that causes problems.

tiff2pdf allocates memory for xref for each image (page) based on the transfer
function it reads for that image (either 2 entries or 4 entries), but it only
keeps track of the last transfer function for the last image it read.

For the first exploit this means it allocates 2 entries for the first image, 2
entries for the second, and 4 entries for the last image. As the transfer
function for the entire file has now been set from the last image, it assumes 4
entries have been allocated for every page, which is not correct, and buffer
overflow occurs.

I think the correct and proper solution is that we need to keep track of a
transfer function for each and every image in the file.

Two possible solutions to this security issue in the meantime however:

1. We always allocate 4 entries for every image. Will solve the buffer overflow
problem, however, may not always give good results as we ignore the transfer
function from earlier images and always use the transfer function from the last
image.

2. We check the transfer function provided by each image matches the previous
images and generate an error if it doesn't. At least this way it is clear to
the user why the operation is not working instead of silently doing the wrong
thing.

I also discussed this on the debian-lts mailing list.
https://lists.debian.org/debian-lts/2017/11/msg00049.html

(note: I have only investigated the POC1 exploit in detail, not the others; for
now I assume they are variations of the same bug)
------- Comment #15 From 2017-11-15 01:35:24 -------
At the moment, the option 2 I listed is my preferred way to solve the security
issue.
------- Comment #16 From 2017-11-15 01:45:40 -------
What is the preferred way of contributing patches to fix this? As attachments
to this bug report?
------- Comment #17 From 2017-11-16 01:40:33 -------
Somewhat puzzled here. I believe a transfer function is a table of 16 bit
integer values. But tiff2pdf.c has:

float* tiff_transferfunction[3];

Did I miss some sort of conversion from uint16 to float?
------- Comment #18 From 2017-12-06 01:18:00 -------
Created an attachment (id=826) [details]
Patch to fix CVE-2017-9935.
------- Comment #19 From 2017-12-06 01:19:01 -------
Created an attachment (id=827) [details]
Patch to fix transfer table type error

Note this depends on the CVE-2017-9935 patch.
------- Comment #20 From 2017-12-06 01:19:41 -------
I have attached patches that I propose to fix the problems I mentioned.
------- Comment #21 From 2017-12-06 12:16:30 -------
Could you open pull requests against https://gitlab.com/libtiff/libtiff with
your patches
------- Comment #22 From 2017-12-06 15:38:14 -------
(In reply to comment #21)
> Could you open pull requests against https://gitlab.com/libtiff/libtiff with
> your patches

Ok, I will have a look.
------- Comment #23 From 2017-12-06 16:09:21 -------
https://gitlab.com/libtiff/libtiff/merge_requests/7
------- Comment #24 From 2017-12-10 16:12:33 -------
(In reply to comment #23)
> https://gitlab.com/libtiff/libtiff/merge_requests/7

My pull request has been merged. Hopefully that means this bug can be closed.
If not, please say so.