Talos Vulnerability Report

TALOS-2017-0309

Kakadu SDK JPEG 2000 Contiguous Codestream Code Execution Vulnerability

August 4, 2017
CVE Number

CVE-2017-2812

Summary

A code execution vulnerability exists in the kdu_buffered_expand function of the Kakadu SDK 7.9. 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.

Tested Versions

Kakadu SDK 7.9 - OSX & Linux

Product URLs

http://kakadusoftware.com/

CVSSv3 Score

8.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

CWE

CWE-131: Incorrect Calculation of Buffer Size

Details

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 when the parser gets to the contiguous codestream section of the Jpeg2000 image. The codestream size is not checked and is overly large leading to excessive parsing of data erroneously. An outline of the vulnerable image is shown below.

    <contiguousCodestreamBox>
        <siz>
            <lsiz>44</lsiz>
            <rsiz>ISO/IEC 15444-1</rsiz>
            <xsiz>268435456</xsiz>
            <ysiz>32</ysiz>
            <xOsiz>0</xOsiz>
            <yOsiz>0</yOsiz>
            <xTsiz>10879008</xTsiz>
        </siz>

As can be seen the size parameters are overly large for a file of only 100 bytes. The program then goes into a loop using these sizes and allocates working buffers based off of the data these sizes point to.

do
{
  data_value = *dataStruct;                    [1]
  size = v160[v86] * data_value << (v186 ^ 1); [2]
  new_size = size + 31;
  v90 = operator new[](new_size);

The vulnerability arises in the fact that after multiple iterations of the loop the data_value being read at [1], is zero thus the size calculation is zero at [2], and the buffer being allocated is of size 31 rather than the necessary size. When this buffer is used again for calculations it access beyond the bounds of the buffer and into memory in various places including potential calls and writes leading to a highly exploitable condition. Using a safe malloc implementation the crash is shown below.

* thread #1: tid = 0x2ca8ece, 0x000000010001209a kdu_buffered_expand`kd_supp_simd::avx2_int16_to_uint8_rs_ilv1(unsigned char*, short**, int, 
int, int, bool, bool, int) + 191,  
queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x100e99000)
    frame #0: 0x000000010001209a kdu_buffered_expand`kd_supp_simd::avx2_int16_to_uint8_rs_ilv1(unsigned char*, short**, int, int, int, bool, bool, 
int) + 191
kdu_buffered_expand`kd_supp_simd::avx2_int16_to_uint8_rs_ilv1:
->  0x10001209a <+191>: vmovdqu ymmword ptr [rdi + 0x20], ymm3
    0x10001209f <+196>: add    ebx, -0x40
    0x1000120a2 <+199>: sub    rsi, -0x80
    0x1000120a6 <+203>: add    rdi, 0x40

Crash Information

Crashed thread log = 
: Dispatch queue: com.apple.main-thread
0   kdu_buffered_expand             0x000000010d19309a kd_supp_simd::avx2_int16_to_uint8_rs_ilv1(unsigned char*, short**, int, int, int, bool, bool, int)   
+ 191
1   kdu_buffered_expand             0x000000010d1873c2 kd_supp_local::kdsd_tile::process(kdu_core::kdu_thread_env*) + 456
2   kdu_buffered_expand             0x000000010d1898ef kdu_supp::kdu_stripe_decompressor::pull_common(int) + 429
3   kdu_buffered_expand             0x000000010d18420c main + 8721
4   libdyld.dylib                   0x00007fff8c2d65ad start + 1
---
exception=EXC_BAD_ACCESS:signal=11:is_exploitable=yes:instruction_disassembly=.byte 0xc5 #bad opcode:instruction_address=0x000000010d19309a:access_type=unknown:access_address=0x000000010df1f000:
Crash accessing invalid address.  

Timeline

2017-04-18 - Vendor Disclosure
2017-08-04 - Public Release

Credit

Discovered by Aleksandar Nikolic and Tyler Bohan of Cisco Talos.