CVE-2016-4629
An exploitable heap based buffer overflow exists in the handling of EXR images on OS X. A crafted EXR document can lead to a heap based buffer overflow resulting in remote code execution. Vulnerability can be triggered via a saved EXR file delivered by other means when opened in any application using the Apple Image I/O API.
OSX El Capitan - 10.11.4
https://developer.apple.com/osx/download
6.4 - CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:L/A:L
This vulnerability is present in the Apple Image I/O API which is used for all image handling on OS X including rendering images in Preview.
There exists a vulnerability in the parsing and handling of EXR images. A specially crafted EXR image file can lead to an out of bounds write and ultimately to remote code execution.
OpenEXR is a high dynamic-range (HDR) image file format developed by Industrial Light & Magic for use in computer imaging applications and is used in all motion pictures currently in production. EXR uses 16-bit floating-point color component values. Since the IEEE-754 floating-point specification does not define a 16-bit format, EXR created the “half” format. Half values have 1 sign bit, 5 exponent bits, and 10 mantissa bits. This information is then read in as rows of x and y coordinates to draw the image. The vulnerability arises when the values read in are not properly sanitized.
The relevant code for the reading of the image is shown below.
```
for (int y = yStart; y <= maxYThisRow; y += toSlice.ySampling)
{
// Set the pointers to the start of the y scanline in
// this row of tiles
fromPtr = fromSlice.base + (y - tileRange.min.y) * fromSlice.yStride + xStart * fromSlice.xStride;
toPtr = toSlice.base +
divp (y, toSlice.ySampling) * toSlice.yStride +
divp (xStart, toSlice.xSampling) * toSlice.xStride; [1]
// Copy all pixels for the scanline in this row of tiles
for (int x = xStart; x <= levelRange.max.x; x += toSlice.xSampling)
{
for (int i = 0; i < size; ++i)
toPtr[i] = fromPtr[i];
fromPtr += fromSlice.xStride * toSlice.xSampling;
toPtr += toSlice.xStride;
}
}
```
The problem here arises when toPtr is calculated, [1], and the values of xStride and yStride are user controlled. If these variables are signed it causes the resulting calculation to be sign extended and points the destination buffer out of bounds. Shown below is where the toPtr is calculated and the corresponding values.
```
RAX: 0xFFFFFFFFDEDEDE00 RBX: 0x00000000DEDEDE00 RBP: 0x00007FFF5FBFA200 RSP: 0x00007FFF5FBFA120 o d I t S z a p c
RDI: 0x00000000DEDEDEDE RSI: 0x0000000000000002 RDX: 0x0000000196C68D20 RCX: 0xFFFFFE3242423620 RIP: 0x0000000168475097
R8: 0x0000000196C68D20 R9: 0x0000000000000002 R10: 0x00000000DEDEDEDE R11: 0x00000000DEDEDE00 R12: 0x0000000100000001
R13: 0x0000000000000002 R14: 0x0000000000000010 R15: 0x00000000DEDEDEDE
libOpenEXR.dylib`Imf_2_2::InputFile::readPixels:
-> 0x168475097 <+1041>: imul rax, r14
0x16847509b <+1045>: add rax, rcx
0x16847509e <+1048>: add rax, qword ptr [rbp - 0x78] [1]
0x1684750a2 <+1052>: mov edi, dword ptr [rbp - 0x4c]
0x1684750a5 <+1055>: mov ecx, 0x0
0x1684750aa <+1060>: test r9d, r9d
0x1684750ad <+1063>: jle 0x1684750c1 ; <+1083>
0x1684750af <+1065>: mov bl, byte ptr [rdx + rcx]
```
Notice RAX is sign extended and contains a very large negative value. When the base of the buffer is added to it, [1], it is pointing well out of bounds, causing an out of bounds write. With proper calculation and set up this vulnerability could potentially be leveraged into a remote code execution vulnerability and give an attacker full control. The resulting crash is shown below.
```
RAX: 0xFFFFFE3196C5C21C RBX: 0x00000000DEDEDEAA RBP: 0x00007FFF5FBFA200 RSP: 0x00007FFF5FBFA120 o d I t s z a p c
RDI: 0x00000000DEDEDE00 RSI: 0x0000000000000002 RDX: 0x0000000196C68D20 RCX: 0x0000000000000000 RIP: 0x00000001684750B2
R8: 0x0000000196C68D20 R9: 0x0000000000000002 R10: 0x00000000DEDEDEDE R11: 0x00000000DEDEDE00 R12: 0x0000000100000001
R13: 0x0000000000000002 R14: 0x0000000000000010 R15: 0x00000000DEDEDEDE
libOpenEXR.dylib`Imf_2_2::InputFile::readPixels:
-> 0x1684750b2 <+1068>: mov byte ptr [rax + rcx], bl
0x1684750b5 <+1071>: add rcx, 0x1
0x1684750b9 <+1075>: cmp esi, ecx
0x1684750bb <+1077>: jne 0x1684750af ; <+1065>
0x1684750bd <+1079>: mov r15d, dword ptr [rbp - 0x30]
0x1684750c1 <+1083>: add rdx, r13
0x1684750c4 <+1086>: add rax, r14
0x1684750c7 <+1089>: add edi, r12d
```
```
Crashed thread log =
: Dispatch queue: com.apple.main-thread
0 libOpenEXR.dylib 0x00000001068b20b2 Imf_2_2::InputFile::readPixels(int, int) + 1068
1 libOpenEXR.dylib 0x000000010693c7d6 exrReadRGBFloat(char const*, int*, int*, unsigned int*, void*) + 621
2 com.apple.ImageIO.framework 0x00007fff8d3460cf copyImageBlockSetOpenEXR + 856
3 com.apple.ImageIO.framework 0x00007fff8d2f40f4 ImageProviderCopyImageBlockSetCallback + 651
4 com.apple.CoreGraphics 0x00007fff93f15cb4 CGImageProviderCopyImageBlockSetWithOptions + 132
5 com.apple.CoreGraphics 0x00007fff93f1739c CGImageProviderCopyImageBlockSet + 205
6 com.apple.CoreGraphics 0x00007fff93f4e7fd img_blocks_create + 517
7 com.apple.CoreGraphics 0x00007fff93f19c9f img_data_lock + 1788
8 com.apple.CoreGraphics 0x00007fff93f186c7 CGSImageDataLock + 151
9 libRIP.A.dylib 0x00007fff933ee1d4 ripc_AcquireImage + 972
10 libRIP.A.dylib 0x00007fff933ecc7e ripc_DrawImage + 1011
11 com.apple.CoreGraphics 0x00007fff93f17c48 CGContextDrawImageWithOptions + 571
12 com.apple.CoreGraphics 0x00007fff93f179f1 CGContextDrawImage + 51
13 com.apple.ImageIO.framework 0x00007fff8d31579e CGImageCreateCopyWithParametersNew + 2575
14 com.apple.ImageIO.framework 0x00007fff8d314b95 CGImageSourceCreateThumbnailAtIndex + 3821
15 com.apple.imageKit 0x00007fff8b1ce044 -[IKImageContentView _newCGImageFromImgSrc:index:displayProperties:imageScale:createBitmapImmediately:] + 747
16 com.apple.imageKit 0x00007fff8b1ce49c __69-[IKImageContentView setImageURL:imageAtIndex:withDisplayProperties:]_block_invoke + 57
17 com.apple.imageKit 0x00007fff8b1ce38b -[IKImageContentView setImageURL:imageAtIndex:withDisplayProperties:] + 799
18 com.apple.Preview 0x0000000101626162 0x10160b000 + 110946
19 com.apple.Preview 0x000000010161fe5d 0x10160b000 + 85597
20 com.apple.Preview 0x0000000101616b47 0x10160b000 + 47943
21 com.apple.AppKit 0x00007fff9978ea2b -[NSWindowController _windowDidLoad] + 592
22 com.apple.AppKit 0x00007fff9972b542 -[NSWindowController window] + 110
23 com.apple.Preview 0x0000000101614d9a 0x10160b000 + 40346
24 com.apple.AppKit 0x00007fff9991b03d -[NSWindowController showWindow:] + 36
25 com.apple.Preview 0x000000010161619e 0x10160b000 + 45470
26 com.apple.Foundation 0x00007fff97316f4e -[NSObject(NSThreadPerformAdditions) performSelector:onThread:withObject:waitUntilDone:modes:] + 1115
27 com.apple.Foundation 0x00007fff97316a75 -[NSObject(NSThreadPerformAdditions) performSelectorOnMainThread:withObject:waitUntilDone:] + 131
28 com.apple.Preview 0x00000001016160df 0x10160b000 + 45279
29 com.apple.Preview 0x0000000101614f13 0x10160b000 + 40723
30 com.apple.Preview 0x00000001016ffdfe 0x10160b000 + 1003006
31 libdispatch.dylib 0x00007fff9c53693d _dispatch_call_block_and_release + 12
32 libdispatch.dylib 0x00007fff9c52b40b _dispatch_client_callout + 8
33 libdispatch.dylib 0x00007fff9c53ec1c _dispatch_main_queue_callback_4CF + 1685
34 com.apple.CoreFoundation 0x00007fff8e4a39e9 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
35 com.apple.CoreFoundation 0x00007fff8e4628dd __CFRunLoopRun + 1949
36 com.apple.CoreFoundation 0x00007fff8e461ed8 CFRunLoopRunSpecific + 296
37 com.apple.HIToolbox 0x00007fff95160935 RunCurrentEventLoopInMode + 235
38 com.apple.HIToolbox 0x00007fff9516076f ReceiveNextEventCommon + 432
39 com.apple.HIToolbox 0x00007fff951605af _BlockUntilNextEventMatchingListInModeWithFilter + 71
40 com.apple.AppKit 0x00007fff9971aefa _DPSNextEvent + 1067
41 com.apple.AppKit 0x00007fff9971a32a -[NSApplication _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 454
42 com.apple.AppKit 0x00007fff9970ee84 -[NSApplication run] + 682
43 com.apple.AppKit 0x00007fff996d846c NSApplicationMain + 1176
44 libdyld.dylib 0x00007fff911725ad start + 1
---
exception=EXC_BAD_ACCESS:signal=11:is_exploitable=yes:instruction_disassembly=movb %bl,(%rax,%rcx):instruction_address=0x00000001068b20b2:access_type=write:access_address=0x00007e214703dc0c:
Crash accessing invalid address. Consider running it again with libgmalloc(3) to see if the log changes.
bootstrap_look_up: (os/kern) unknown error code (44e)
+ EXIT_VALUE=255
+ exit 255
```
2016-05-16 - Vendor Disclosure
2016-07-18 - Public Release
Tyler Bohan of Cisco Talos