Talos Vulnerability Report

TALOS-2019-0884

LEADTOOLS DICOM UI Parsing Code Execution Vulnerability

December 10, 2019
CVE Number

CVE-2019-5092

Summary

An exploitable heap out of bounds write vulnerability exists in the UI tag parsing functionality of the DICOM image format of LEADTOOLS 20. A specially crafted DICOM image can cause an offset beyond the bounds of a heap allocation to be written, potentially resulting in code execution. An attacker can specially craft a DICOM image to trigger this vulnerability.

Tested Versions

LEADTOOLS 20.0.2019.3.15

Product URLs

https://www.leadtools.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-787 - Out-of-bounds Write

Details

LEADTOOLS, according to the website, "is a collection of comprehensive toolkits to integrate document, medical, multimedia, and imaging technologies into desktop, server, tablet, and mobile applications". It offers prebuilt and portable libraries with an SDK for most platforms (Windows, Linux, Android, etc), that are all geared towards building applications for medical systems.

The module analyzed in this vulnerability is below:

Loaded symbol image file: C:\LEADTOOLS 20\Bin\CDLL\x64\ltdicx.dll
Image path: C:\LEADTOOLS 20\Bin\CDLL\x64\ltdicx.dll
Image name: ltdicx.dll
Browse all global symbols  functions  data
Timestamp:        Fri Mar  1 14:52:51 2019 (5C799BA3)
CheckSum:         0017C012
ImageSize:        00179000
File version:     20.0.0.41
Product version:  20.0.0.0

One toolkit provided by LEADTOOLS is a DICOM image parser. LEADTOOLS has a variety of prebuilt applications that leverage the DICOM library, including a direct image viewer and several DICOM servers.

Data in the DICOM format is formatted in a series of data structures. These data structures have various value representations (VR). Each VR describes the data type and format for that particular Data Element's value. The UI tag (0x5549) includes a size field as well as the data immediately afterwards. An allocation occurs based on the size of the UI element.

ltdicx+4db48
.text:04DB48 8D 4D 01                lea     ecx, [rbp+1]    ; rcx - Size of UI element
.text:04DB4B FF 15 77 8A 11 00       call    L_LocalAlloc    ; 

After the buffer is allocated, during the handling of the UI tag, there is a check if a backslash ('\') exists in the data buffer. If there is a backslash, it is replaced with a null in order to find the length of the substring ending in the backslash. The backslash is then replaced in order to calculate the length of the full data buffer by looking for an ending null byte.

ltdicx+4e3b0
.text:04E3B0  mov     edx, '\'        
.text:04E3B5  mov     rcx, rsi           ; Data buffer
.text:04E3B8  call    strchr             ; Find '\' in the data buffer
.text:04E3BD  mov     rdi, rax
.text:04E3C0  test    rax, rax
.text:04E3C3  jz      short loc_4E3C8
.text:04E3C5  mov     byte ptr [rax], 0  ; Replace '\' with a null
.text:04E3C8  mov     rdx, rsi        
.text:04E3CB  mov     rcx, r13        
.text:04E3CE  call    LDicomDS::DelSpaces ; Delete any spaces in the data buffer 
.text:04E3D3  test    rdi, rdi
.text:04E3D6  jz      short loc_4E40C
.text:04E3D8  mov     byte ptr [rdi], '\' ; Return data buffer to original state
.text:04E3DB  mov     rax, rbp
.text:04E3DE  inc     rdi
.text:04E3E1  cmp     byte ptr [rdi+rax+1], 0 ; Find the length of the substring after '\'
.text:04E3E6  lea     rax, [rax+1]
.text:04E3EA  jnz     short loc_4E3E1
.text:04E3EC  lea     r8d, [rax+1]            ; [0]
.text:04E3F0  mov     rax, rbp
.text:04E3F3  cmp     byte ptr [rsi+rax+1], 0 ; Find the length of the data buffer
.text:04E3F8  lea     rax, [rax+1]

With the length of the data buffer and the length of the substring calculated, memmove is called to copy the second substring into the data buffer itself. The size of memmove is calculated and stored above [0].

ltdicx+4ed401
.text:04E401                 mov     rdx, rdi        ; Second substring
.text:04E404                 add     rcx, rsi        ; Offset into the data buffer
.text:04E407                 call    memmove

It is possible for an attacker to allocate a small enough buffer to hold the data after the memmove. The memmove will write data outside the bounds of the heap allocation, causing a heap based buffer overflow, potentially resulting in code execution.

Crash Information

ltdicx!L_DicomChannelDeleteAnnotation+0x83b9:
00007ffd`30260b19 0f1101          movups  xmmword ptr [rcx],xmm0 ds:00000272`d71e9ffb=????????????????????????????????

>>> analyze -v
MODULE_NAME: ltdicx
IMAGE_NAME:  ltdicx.dll
DEBUG_FLR_IMAGE_TIMESTAMP:  5c799ba3
FAILURE_BUCKET_ID:  INVALID_POINTER_WRITE_AVRF_c0000005_ltdicx.dll!L_DicomChannelDeleteAnnotation
BUCKET_ID:  APPLICATION_FAULT_INVALID_POINTER_WRITE_AVRF_ltdicx!L_DicomChannelDeleteAnnotation+83b9
FAILURE_EXCEPTION_CODE:  c0000005

Timeline

2019-08-08 - Vendor Disclosure
2019-09-06 - 30 day follow up with vendor re: case number assigned
2019-09-09 - Vendor acknowledged issue under review
2019-10-21 - 60+ day follow up
2019-12-05 - Vendor patched
2019-12-10 - Public Release

Credit

Discovered by Marcin Towalski and Cory Duplantis of Cisco Talos.