CVE-2016-8331
{{ page.status }}
An exploitable remote code execution vulnerability exists in the handling of TIFF images in LibTIFF. A crafted TIFF document can lead to a type confusion vulnerability resulting in remote code execution. This vulnerability can be triggered via a TIFF file delivered to the application using LibTIFF’s tag extension functionality.
LibTIFF - 4.0.6
http://www.remotesensing.org/libtiff/
8.1 - CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H
There exists a vulnerability in the parsing and handling of TIFF images. A specially crafted TIFF image file can lead to an out of bounds write and ultimately to remote code execution. This vulnerability is present in the LibTIFF api and is present in the standard build.
TIFF offers support for tag extensions allowing for more tags than the standard TIFF specification. One such tag is number 326, BadFaxLines. When using this tag in LibTIFF it is possible to have a type confusion vulnerability where LibTIFF attempts to read a mistyped argument off of the variable argument list. Running the provided trigger through the Thumbnail utility provided by LibTIFF gives us the following crash.
1130 case TIFF_DOUBLE:
-> 1131 *va_arg(ap, double*) =
1132 *(double *)val;
(lldb) h
-=[registers]=-
[rax: 0x00000001003002d0] [rbx: 0x0000000000000146] [rcx: 0x0000390000003a03]
[rdx: 0x0000000000000020] [rsi: 0x0000000000000018] [rdi: 0x0000000100300170]
[rsp: 0x00007fff5fbff8e0] [rbp: 0x00007fff5fbff910] [ pc: 0x000000010001e08b]
[ r8: 0x0000000000000040] [ r9: 0x00007fff71d71110] [r10: 0xffffffffffffffff]
[r11: 0x0000000000000246] [r12: 0x0000000000000000] [r13: 0x0000000100300110]
[r14: 0x00007fff5fbff9d0] [r15: 0x0000000000000000] [efl: 0x0000000000010202]
[rflags: 00000000 NZ NS NO NC ND NI]
-=[stack]=-
7fff5fbff8e0 | 0000000000000001 0000000101002c00 | .........,......
7fff5fbff8f0 | eb008c3017da5776 0000000101002c00 | vW..0....,......
7fff5fbff900 | 0000000000000146 0000000000000000 | F...............
7fff5fbff910 | 00007fff5fbffa10 0000000100011338 | ..._....8.......
-=[disassembly]=-
0x10001e080 <+9504>: lea rsp, [rsp + 0x98]
0x10001e088 <+9512>: mov rcx, qword ptr [rcx]
-> 0x10001e08b <+9515>: mov qword ptr [rcx], rax
0x10001e08e <+9518>: jmp 0x10001e30e ; <+10158> at tif_dir.c:855
0x10001e093 <+9523>: nop word ptr cs:[rax + rax]
0x10001e0a0 <+9536>: lea rsp, [rsp - 0x98]
(lldb) bt
* thread #1: tid = 0x3008d362, 0x000000010001e08b libtiff.5.dylib`_TIFFVGetField(tif=<unavailable>, tag=326, ap=<unavailable>) + 9515 at tif_dir.c:1131, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x390000003a03)
* frame #0: 0x000000010001e08b libtiff.5.dylib`_TIFFVGetField(tif=<unavailable>, tag=326, ap=<unavailable>) + 9515 at tif_dir.c:1131
frame #1: 0x0000000100011338 libtiff.5.dylib`TIFFGetField [inlined] TIFFVGetField(tif=0x0000000101002c00, tag=326) + 335 at tif_dir.c:1176
frame #2: 0x00000001000111e9 libtiff.5.dylib`TIFFGetField(tif=0x0000000101002c00, tag=326) + 345 at tif_dir.c:1160
frame #3: 0x0000000100001c7b thumbnail`main + 12 at thumbnail.c:178
frame #4: 0x0000000100001c6f thumbnail`main [inlined] cpTags at thumbnail.c:310
frame #5: 0x0000000100001c6f thumbnail`main [inlined] cpIFD at thumbnail.c:386
frame #6: 0x0000000100001c6f thumbnail`main(argc=<unavailable>, argv=<unavailable>) + 2415 at thumbnail.c:133
frame #7: 0x00007fff8260f5ad libdyld.dylib`start + 1
frame #8: 0x00007fff8260f5ad libdyld.dylib`start + 1
The crash occurs at the following lines of code:
tif_dir.c
1130 case TIFF_DOUBLE:
-> 1131 *va_arg(ap, double*) =
1132 *(double *)val;
Recall that va_arg
retrieves the next available argument from the argument list ap
. Let’s take a look at where this function was called.
int
TIFFGetField(TIFF * tif, uint32 tag, ...)
{
int status;
va_list ap;
va_start(ap, tag)
status = TIFFVGetField(tif, tag, ap); // Crash happens here
va_end(ap);
return (status);
}
We see that we are passing in the variable argument list from TIFFGetField into TIFFVGetField. Effectively this is a wrapper for creating the variable list that will be handled by each individual tag. Let’s traverse up one more function to see how TIFFGetField
is called.
tools/thumbnail.c
136 #define CopyField(tag, v) \
137 if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
165 case TIFF_LONG:
166 { uint32 longv;
167 CopyField(tag, longv); // Call to TIFFGetField
168 }
169 break;
Analyzing the crash a bit we can see the tag that we are crashing on is indeed number 326. Looking into the source we can see a double value is expected on the argument list but instead there is nothing there.
tif_dir.c:599
switch (fip->field_type) {
...
tif_dir.c:659
case TIFF_DOUBLE:
*va_arg(ap, double*) =
*(double *)val;
ret_val = 1;
break;
default:
ret_val = 0;
break;
}
The vulnerability arises due to the field type being determined to be a double, yet the variable argument list is empty causing an out of bounds write and ultimately leading to an exploitable condition.
Crashed thread log =
: Dispatch queue: com.apple.main-thread
0 libtiff.5.dylib 0x00000001045ea5e0 _TIFFVGetField + 2784 (tif_dir.c:1132)
1 libtiff.5.dylib 0x00000001045e774b TIFFGetField + 219 (tif_dir.c:1177)
2 thumbnail 0x00000001045d8c7b main + 2427 (thumbnail.c:178)
3 libdyld.dylib 0x00007fff8260f5ad start + 1
log name is: ./crashlogs/libtiff-thumbnail-report_badfaxlines_tif.crashlog.txt
---
exception=EXC_BAD_ACCESS:signal=11:is_exploitable=yes:instruction_disassembly=movq %rax,(%rcx):instruction_address=0x00000001045ea5e0:access_type=write:access_address=0x0000430000004403:
Crash accessing invalid address. Consider running it again with libgmalloc(3) to see if the log changes.
2016-07-25 - Vendor Disclosure
2016-10-25 - Public Release
Tyler Bohan and Cory Duplantis