A code execution vulnerability exists in the Kakadu SDK 7.9’s parsing of compressed JPEG 2000 images. A specially crafted JPEG 2000 file can be read by the program, and can lead to an out of bounds write causing an exploitable condition to arise.
Kakadu SDK 7.9 - OSX & Linux
8.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
CWE-131: Incorrect Calculation of Buffer Size
Kakadu SDK is a commercial solution for the parsing and handling of JPEG 2000 images. This software is used by many high profile companies in the handling of JPEG 2000 images, including Apple. This vulnerability could have a large impact due to the number of users using this SDK to handle their images.
The JPEG 2000 format begins with a header describing the data that will be presented in the rest of the file. The header is parsed by scanning through, finding a marker, and parsing the data based off of the type of marker. The size of the current markers data is presented immediately following the marker itself. The vulnerability arises in the handling of an unknown marker.
The hex dump of the trigger file is shown below.
ff4f ff51 002f 0000 0000 0020 0000 00f3 0000 000d 0000 0000 0000 02d0 0000 0040 0000 0000 0000 0000 0003 0701 0107 0201 0702 7cff 5200 0c00 0000 0100 0400 0327 2cff 7900 2330 2c01 0000 001a 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
The first two bytes represent a signature then the next two begin the marker parsing. Marker ids begin with 0xFF and the byte following determines the type of marker. Following the marker type the next two bytes represent the size of the field. If we take the size of the first marker id it brings us to the next id of FF52 with a size of 0xC. Then finally we get to the unknown marker id of 0xFF79. Due to this being an unknown marker, the size field is calculated and taken from the fourth byte and is read in as 0x0000001A00000001. The code for creating the working buffer is shown below.
v9 = *(_QWORD *)&this->calc_size; v11 = HIDWORD(v9) * v9; kdu_core::kdu_kernels::enlarge_work_buffers(this, v11);
And inside enlarge_work_buffers:
if ( is_mul_ok(4uLL, 2 * a2 + 1) ) v3 = 4LL * (2 * a2 + 1); new_buffer = operator new(v3); v7 = new_buffer + 4LL * a2; this->data_buffer = v7; 
So from this we can derive that the size of the created buffer is 212 or (0x1a*2+1) * 4. At,1, we can see the newly allocated buffer being put into the structure for use later. Oddly, the buffer is advanced by 104 bytes before being assigned. Later on in the program when this buffer is used again, the same calculations are performed and an attempt to zero out the buffer for a size of 212 is made. As can be seen above this will cause a buffer overflow and lead to an exploitable out-of-bounds write condition.
Crashed thread log = : Dispatch queue: com.apple.main-thread 0 libsystem_platform.dylib 0x00007fff91a4bc74 _platform_bzero$VARIANT$Haswell + 84 1 libkdu_v79R.dylib 0x0000000103749b13 kdu_core::kdu_kernels::get_bibo_gains(int, int, bool*, double&, double&) + 1539 2 libkdu_v79R.dylib 0x000000010372fefb kd_core_local::kd_resolution::build_decomposition_structure(kdu_core::kdu_params*, kdu_core::kdu_kernels&) + 1979 3 libkdu_v79R.dylib 0x000000010372c020 kd_core_local::kd_tile::initialize() + 5712 4 libkdu_v79R.dylib 0x00000001037168d6 kd_core_local::kd_codestream::create_tile(kdu_core::kdu_coords) + 470 5 libkdu_v79R.dylib 0x00000001037260e7 kdu_core::kdu_codestream::open_tiles(kdu_core::kdu_dims, bool, kdu_core::kdu_thread_env*) + 1175 6 kdu_buffered_expand 0x00000001036b4a4d kdu_supp::kdu_stripe_decompressor::augment_started_queues() + 223 7 kdu_buffered_expand 0x00000001036b57e5 kdu_supp::kdu_stripe_decompressor::pull_common(int) + 163 8 kdu_buffered_expand 0x00000001036b020c main + 8721 9 libdyld.dylib 0x00007fff8c2d65ad start + 1 --- exception=EXC_BAD_ACCESS:signal=11:is_exploitable=yes:instruction_disassembly=.byte 0xc5 #bad opcode:instruction_address=0x00007fff91a4bc74:access_type=unknown:access_address=0x0000000104450000: Crash accessing invalid address.
2017-04-18 - Vendor Disclosure
2017-08-04 - Public Release
Discovered by Aleksandar Nikolic and Tyler Bohan of Cisco Talos.