Talos Vulnerability Report

TALOS-2018-0670

AutoDesk AutoCAD 2019 DXF-parsing code execution vulnerability

February 14, 2019
CVE Number

CVE-2019-7358

Summary

An exploitable heap overflow vulnerability exists in the DXF-parsing functionality of AutoDesk AutoCAD 2019 P.46.0.0. A specially crafted DXF file can cause a heap overflow, resulting in code execution. An attacker must convince a victim to open a malicious document in order to trigger this vulnerability.

Tested Versions

AutoDesk AutoCAD 2019 P.46.0.0

Product URLs

https://www.autodesk.com/products/autocad/overview

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-122: Heap-based Buffer Overflow

Details

AutoDesk AutoCAD is a design and drafting application. AutoCAD helps civil engineers draft practically any civil engineering structure with ease, speed, and accuracy. This application also helps engineers solve design issues earlier in the design process before too much time and money is invested.

One of the file formats AutoCAD supports is drawing exchange format (DXF). DXF was developed by AutoDesk to help pass data between the variety of AutoDesk applications. The format is a tagged, where each data element is prepended with a number that represents a group code signifying how the data is interpreted.

The module used for analysis is:

0:000> lm vm acdb23
start             end                 module name
00007ffd`bc550000 00007ffd`bda40000   acdb23     (export symbols)       C:\Program Files\Autodesk\AutoCAD 2019\acdb23.dll
    Loaded symbol image file: C:\Program Files\Autodesk\AutoCAD 2019\acdb23.dll
    Image path: C:\Program Files\Autodesk\AutoCAD 2019\acdb23.dll
    Image name: acdb23.dll
    Timestamp:        Mon Jan 29 20:32:20 2018 (5A6FF554)
    CheckSum:         014D5C2F
    ImageSize:        014F0000
    File version:     23.0.46.0
    Product version:  23.0.46.0

While parsing the DXF format and the 310 group code, the parser attempts to allocate space for the binary data following the group code. Before allocating space for the data, this is used to calculate the size of the buffer:

acdb23.dll+0x6ec23d
.text:00000000016EC23D                             
.text:00000000016EC23D  mov     r13, [rax+120h]
.text:00000000016EC244  mov     rcx, r13        ; [0]
.text:00000000016EC247  call    sub_1042B80     ; Get size of buffer
.text:00000000016EC24C  mov     esi, eax

The data after the 310 group code is passed to the function sub_1042B80 [0]:

acdb23.dll+0x42b80
.text:0000000001042B80  sub_1042B80     
.text:0000000001042B80                                           
.text:0000000001042B80  xor     eax, eax
.text:0000000001042B82  cmp     [rcx], ax
.text:0000000001042B85  jz      short locret_1042B9C
.text:0000000001042B87  nop     word ptr [rax+rax+00000000h]
.text:0000000001042B90
.text:0000000001042B90  loc_1042B90:                            
.text:0000000001042B90  lea     rcx, [rcx+2]
.text:0000000001042B94  inc     eax
.text:0000000001042B96  cmp     word ptr [rcx], 0
.text:0000000001042B9A  jnz     short loc_1042B90
.text:0000000001042B9C
.text:0000000001042B9C  locret_1042B9C:                         
.text:0000000001042B9C  retn
.text:0000000001042B9C  sub_1042B80     endp

This function effectively calculates the length of the buffer in order know how much memory to allocate. With the size in hand, the parser allocates memory to process the data:

acdb23.dll+0x6ec247
.text:00000000016EC247  call    sub_1042B80    ; Get length of data
.text:00000000016EC24C  mov     esi, eax
.text:00000000016EC24E  mov     dword ptr [rbp+arg_0], eax
.text:00000000016EC251  add     eax, r14d      ; r14d = 1
.text:00000000016EC254  cwde
.text:00000000016EC255  cdq
.text:00000000016EC256  mov     r12d, 2
.text:00000000016EC25C  idiv    r12d
.text:00000000016EC25F  mov     [rdi+10h], ax
.text:00000000016EC263  test    ax, ax
.text:00000000016EC266  movsx   ecx, ax
.text:00000000016EC269  jg      short loc_16EC26E
.text:00000000016EC26B  mov     ecx, r14d       ; If size < 0, ecx = 1
.text:00000000016EC26E
.text:00000000016EC26E  loc_16EC26E:           
.text:00000000016EC26E  movsxd  rcx, ecx        ; Size
.text:00000000016EC271  call    cs:malloc       

The returned size from the length function is then incremented by one, and then divided by two since the data was processed as words and not bytes. After the division, is the result is less than zero, then only one byte is allocated. Before the division, but after the increment, there is a sign extension via cwde. If the result of the length function is 0x7fff, then the increment causes an overflow to 0x8000 which is then sign extended to 0xffff8000. This value, even after the division is still less than zero, resulting in a one byte allocation.

Following the allocation is a population of the resulting malloc'ed buffer.

acdb23.dll+0x6ec277
.text:00000000016EC277  mov     r14, rax
.text:00000000016EC27A  mov     [rdi+18h], rax
.text:00000000016EC27E  test    esi, esi
.text:00000000016EC280  jle     loc_16EC335
.text:00000000016EC286
.text:00000000016EC286  loc_16EC286:                            ; CODE XREF: sub_16EBE6C+47B↓j
.text:00000000016EC286  movzx   esi, word ptr [r13+0]
.text:00000000016EC28B  add     r13, r12
.text:00000000016EC28E  movzx   ecx, si         
.text:00000000016EC291  call    cs:iswdigit     ; [3]
.text:00000000016EC297  test    eax, eax
.text:00000000016EC299  jz      short loc_16EC2A7
.text:00000000016EC29B  movzx   ecx, si
.text:00000000016EC29E  call    sub_10D9BF8
.text:00000000016EC2A3  mov     esi, eax
.text:00000000016EC2A5  jmp     short loc_16EC2CB
.text:00000000016EC2A7
.text:00000000016EC2A7  loc_16EC2A7:                            ; CODE XREF: sub_16EBE6C+42D↑j
.text:00000000016EC2A7  lea     eax, [rsi-61h]
.text:00000000016EC2AA  mov     ecx, 5
.text:00000000016EC2AF  cmp     ax, cx
.text:00000000016EC2B2  ja      short loc_16EC2BB
.text:00000000016EC2B4  mov     eax, 0FFA9h
.text:00000000016EC2B9  jmp     short loc_16EC2C8
.text:00000000016EC2BB
.text:00000000016EC2BB  loc_16EC2BB:                            ; CODE XREF: sub_16EBE6C+446↑j
.text:00000000016EC2BB  lea     eax, [rsi-41h]
.text:00000000016EC2BE  cmp     ax, cx
.text:00000000016EC2C1  ja      short loc_16EC2EB
.text:00000000016EC2C3  mov     eax, 0FFC9h
.text:00000000016EC2C8  
.text:00000000016EC2C8  loc_16EC2C8:                            ; CODE XREF: sub_16EBE6C+44D↑j
.text:00000000016EC2C8  add     si, ax
.text:00000000016EC2CB
.text:00000000016EC2CB  loc_16EC2CB:                            ; CODE XREF: sub_16EBE6C+439↑j
.text:00000000016EC2CB  test    r15b, 1
.text:00000000016EC2CF  jnz     short loc_16EC2DA
.text:00000000016EC2D1  shl     sil, 4
.text:00000000016EC2D5  mov     [r14], sil      ; [2]
.text:00000000016EC2D8  jmp     short loc_16EC2E0

The population of the resulting buffer [2] continues until there isn't a valid wide character [3]. This causes a heap overflow potentially resulting in code execution in the context of the AutoCAD process.

Crash Information

0:000> r
rax=000000000000ffa9 rbx=000001a452bd4e90 rcx=0000000000000005
rdx=0000000000000004 rsi=00000000000000a0 rdi=000001a452bd4ea0
rip=00007ff93218c2d5 rsp=000000219cdfb8e0 rbp=000000219cdfb920
r8=0000000000000007  r9=0000000000000000 r10=000001a3a5912ff0
r11=000001a3a56c8d20 r12=0000000000000002 r13=000001a453091fda
r14=000001a3a5913000 r15=0000000000000020
iopl=0         nv up ei ng nz na po nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010286
acdb23!AcDbR13DxfInController::~AcDbR13DxfInController+0x79e5:
00007ff9`3218c2d5 418836          mov     byte ptr [r14],sil ds:000001a3`a5913000=??

0:000> db r14-10
000001a3`a5912ff0  47 2a aa aa aa aa aa aa-aa aa aa aa aa aa aa aa  G...............
000001a3`a5913000  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
000001a3`a5913010  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????

Timeline

2018-10-02 - Vendor Disclosure
2019-02-14 - Public Release

Credit

Discovered by Cory Duplantis of Cisco Talos.