Talos Vulnerability Report

TALOS-2017-0269

National Instruments LabVIEW LvVarientUnflatten Code Execution Vulnerability

March 22, 2017
CVE Number

CVE-2017-2775

Summary

An exploitable memory corruption vulnerability exists in the LvVarientUnflatten functionality of LabVIEW 2016 version 16.0.0.49152. A specially crafted VI file can cause a user controlled value to be used as a loop terminator resulting in internal heap corruption. An attacker controlled VI file can be used to trigger this vulnerability, exploitation could lead to remote code execution.

Tested Versions

LabVIEW 2016 Evaluation (version 16.0.0.49152)

Product URLs

http://www.ni.com/labview/

CVSSv3 Score

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

CWE

CWE-122: Heap-based Buffer Overflow

Details

LabVIEW provides engineers a simple environment to build measurement or control systems. LabVIEW is used to abstract many of the low-level details of various hardware and signal-processing libraries into a single platform. It uses a graphical programming approach to achieve this goal.

Modules utilized in this vulnerability:

start             end                 module name
00000000`0ae60000 00000000`0b02c000   tdcore_16_0   (deferred)
	Image path: C:\Program Files\National Instruments\LabVIEW 2016\resource\tdcore_16_0.dll
	Image name: tdcore_16_0.dll
	Browse all global symbols  functions  data
	Timestamp:        Wed Jun 08 11:51:42 2016 (57585B2E)
	CheckSum:         001CF8D0
	ImageSize:        001CC000
	Translations:     0000.04b0 0000.04e4 0409.04b0 0409.04e4

start             end                 module name
00000000`04f70000 00000000`05069000   mgcore_SH_16_0   (deferred)
	Image path: C:\Program Files\National Instruments\LabVIEW 2016\resource\mgcore_SH_16_0.dll
	Image name: mgcore_SH_16_0.dll
	Browse all global symbols  functions  data
	Timestamp:        Wed Jun 08 11:00:25 2016 (57584F29)
	CheckSum:         000E3FEE
	ImageSize:        000F9000
	File version:     16.0.0.49152
	Product version:  16.0.0.49152
	File flags:       0 (Mask 3F)
	File OS:          40004 NT Win32
	File type:        2.0 Dll
	File date:        00000000.00000000
	Translations:     0409.04b0
	CompanyName:      National Instruments Corporation
	ProductName:      MGCOREDLL_SH
	InternalName:     MGCOREDLL_SH 16.0.0f0
	OriginalFilename: mgcore_SH_16_0.dll
	ProductVersion:   16.0.0f0
	FileVersion:      16.0.0f0
	FileDescription:  LabVIEW NonUI Managers
	LegalCopyright:   Copyright © 2000-2016 National Instruments Corporation. All Rights Reserved.
	Comments:         2016/06/08 11:29:22, mgcore_SH_16_0/win64U/x64/msvc90/release

During the unflattening of a LvVarient object, a call to ReadTD occurs [0]:

tdcore_16_0!LvVariant::UnFlatten+0x19c
.text:0000000000815281     loc_815281:                             ; DATA XREF: .rdata:stru_93F5A0o
.text:0000000000815281 108                 mov     rax, [rdi]
.text:0000000000815284 108                 lea     rdx, [rsp+108h+readTD_obj]
.text:0000000000815289 108                 mov     rcx, rdi
.text:000000000081528C 108                 call    qword ptr [rax+0E0h] ; ReadTD [0]

During this ReadTD, various pieces of the input file is read using ReadU32 from a BinDataReader [1]. This object provides an interface to an open file handle to read input in various formats. In this case, an unsigned 32 bit integer is being read from the file.

tdcore_16_0!TDDataReader::ConstructEltTD+0x4c3
TDDataReader::ConstructEltTD(void)+4BA
TDDataReader::ConstructEltTD(void)+4BA      loc_826C7A:                             ; CODE XREF: TDDataReader::ConstructEltTD(void)+458j
TDDataReader::ConstructEltTD(void)+4BA  0F8                 mov     rax, [rcx]
TDDataReader::ConstructEltTD(void)+4BD  0F8                 mov     rdx, rdi
TDDataReader::ConstructEltTD(void)+4C0  0F8                 call    qword ptr [rax+78h] ; BinDataReader::ReadU32 [1]
TDDataReader::ConstructEltTD(void)+4C3  0F8                 test    eax, eax
TDDataReader::ConstructEltTD(void)+4C5  0F8                 jz      short loc_826CE7

While parsing the LastSavedTarget segment of the input file, four bytes are read which are used as a loop condition in which ClearMem is called over chunks of the heap structure internal to LabVIEW.

tdcore_16_0!TDArrayBaseImp::PrintDebugStr+0x8f1
.text:000000000083B291     loop:
.text:000000000083B291 088                 mov     rax, [r13+0]
.text:000000000083B295 088                 mov     r10, [r12]
.text:000000000083B299 088                 mov     r9d, 1
.text:000000000083B29F 088                 mov     rcx, [rax]
.text:000000000083B2A2 088                 mov     r8d, r15d
.text:000000000083B2A5 088                 mov     dword ptr [rsp+88h+var_68], ebp
.text:000000000083B2A9 088                 lea     rdx, [rbx+rcx]
.text:000000000083B2AD 088                 mov     rcx, r12
.text:000000000083B2B0 088                 call    qword ptr [r10+0B0h] ; Calls ClearMem
.text:000000000083B2B7 088                 test    eax, eax
.text:000000000083B2B9 088                 jnz     short return_result
.text:000000000083B2BB 088                 movsxd  rax, r14d
.text:000000000083B2BE 088                 inc     rdi
.text:000000000083B2C1 088                 add     rbx, rax
.text:000000000083B2C4 088                 cmp     rdi, rsi
.text:000000000083B2C7 088                 jb      short loop
.text:000000000083B2C9     counter_terminated:
.text:000000000083B2C9 088                 xor     eax, eax
.text:000000000083B2CB 088                 jmp     short return_result
.text:000000000083B2CD     return_2:
.text:000000000083B2CD 088                 mov     eax, 2
.text:000000000083B2D2     return_result:
.text:000000000083B2D2 088                 mov     rsi, [rsp+88h+arg_18]

tdcore_16_0!TDImpClearMemory+0x5
.text:0000000000821465 000                 push    rbx
.text:0000000000821466 008                 sub     rsp, 20h
.text:000000000082146A 028                 mov     rax, [rdx]
.text:000000000082146D 028                 mov     r9, rdx
.text:0000000000821470 028                 mov     rbx, rcx
.text:0000000000821473 028                 xor     edx, edx
.text:0000000000821475 028                 mov     rcx, r9
.text:0000000000821478 028                 call    qword ptr [rax+90h] ; returns 8
.text:000000000082147E 028                 mov     rcx, rbx ; Internal heap address
.text:0000000000821481 028                 movsxd  rdx, eax ; 8
.text:0000000000821484 028                 call    ClearMem


 mgcore_SH_16_0!ClearMem:
 ClearMem_233168       000                 sub     rsp, 28h
 ClearMem_233168+4     028                 mov     r8, rdx         ; Size
 ClearMem_233168+7     028                 xor     edx, edx        ; Val
 ClearMem_233168+9     028                 call    memset

In each iteration of the loop, the current internal heap address is cleared in 8 byte chunks and incremented to the next heap address. By supplying an invalid loop termiator, an attacker can clear internal heap chunks which could potentially lead to remote code execution.

Crash Information

rax=000000000bf0c000 rbx=000000000bf0c000 rcx=000000000bf0c000
rdx=0000000000000000 rsi=00000000069390c0 rdi=000000000bf0c000
rip=000000007328e5d0 rsp=000000000042c4c8 rbp=0000000000000000
r8=0000000000000000  r9=0000000000000001 r10=0000000002b0db38
r11=0000000000000000 r12=00000000069390c0 r13=000000000bf07820
r14=0000000000000008 r15=0000000000000000
iopl=0         nv up ei pl nz na pe nc
MSVCR90+0x1e5d0:
00000000`7328e5d0 488911          mov     qword ptr [rcx],rdx ds:00000000`0bf0c000=????????????????

00000000`7328e5bc 7539            jne     MSVCR90+0x1e5f7 (00000000`7328e5f7)
00000000`7328e5be 4d8bc8          mov     r9,r8
00000000`7328e5c1 4983e007        and     r8,7
00000000`7328e5c5 49c1e903        shr     r9,3
00000000`7328e5c9 7411            je      MSVCR90+0x1e5dc (00000000`7328e5dc)
00000000`7328e5cb 66666690        xchg    ax,ax
00000000`7328e5cf 90              nop
MSVCR90+0x1e5d0:
00000000`7328e5d0 488911          mov     qword ptr [rcx],rdx                    ⇐ instruction pointer

Timeline

2017-01-13 - Vendor Disclosure
2017-03-22 - Public Release

Credit

Cory Duplantis