Talos Vulnerability Report

TALOS-2018-0545

Microsoft wimgapi LoadIntegrityInfo Code Execution Vulnerability

June 12, 2018
CVE Number

CVE-2018-8210

Summary

An exploitable heap corruption exists in the LoadIntegrityInfo function of wimgapi version 10.0.16299.15 (WinBuild.160101.0800). A crafted WIM image can lead to a heap corruption, resulting in direct code execution.

Tested Versions

WIMGAPI 10.0.16299.15 (WinBuild.160101.0800)

Product URLs

https://www.microsoft.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-122: Heap-based Buffer Overflow

Details

This vulnerability is present in the wimgapi DLL, which is used for performing operations on Windows Imaging Forma (WIM) files.
WIM is a file-based disk image format created by Microsoft to simplify the deployment of Windows systems. There is a vulnerability in the LoadIntegrityInfo function that manifests during the parsing of the WIM file header. A specially crafted WIM file can lead to a heap corruption and remote code execution. The vulnerability triggers even on the simplest operations performed on malformed WIM file because its related to file header parsing. It triggers just after we try to obtain a WIM file handle via:

hWim = WIMCreateFile(pszWimFile.c_str(),          // Path to existing .wim file
    WIM_GENERIC_READ,    // Access mode
    WIM_OPEN_EXISTING,   // Open disposition
    dwCreateFlags,
    0,                   // Compression type is ignored for WIM_OPEN_EXISTING.
    &dwCreateResult);

Internally, the wimgapi will try to load part of the WIM header, which is the Integrity Table Layout. This operation is performed in the LoadIntegrityInfo function:

Line 1  signed int __thiscall LoadIntegrityInfo(void *this)
Line 2  {
Line 3    void *v1; // edi
Line 4    signed int v2; // esi
Line 5    _WIMHEADER_V1_PACKED *wimHeader; // eax MAPDST
Line 6    __int64 v5; // rax
Line 7    SIZE_T uncompressSize; // ST10_4
Line 8    HANDLE v7; // eax
Line 9    LPVOID uncompressBuffer; // eax
Line 10   void *v9; // ebx
Line 11   signed int v10; // eax
Line 12   DWORD v11; // esi
Line 13   NTSTATUS v12; // ST08_4
Line 14   int v13; // eax
Line 15   HANDLE v14; // eax
Line 16   DWORD nNumberOfBytesToWrite; // [esp+Ch] [ebp-Ch]
Line 17   int v17; // [esp+10h] [ebp-8h]
Line 18
Line 19   v1 = this;
Line 20   v2 = 1;
Line 21   wimHeader = (_WIMHEADER_V1_PACKED *)GetWimHeader(this);
Line 22   if ( v1 )
Line 23   {
Line 24     LODWORD(v5) = *(_DWORD *)wimHeader->rhIntegrity.size_in_wim;
Line 25     HIDWORD(v5) = *(_DWORD *)&wimHeader->rhIntegrity.size_in_wim[4];
Line 26     nNumberOfBytesToWrite = v5;
Line 27     if ( v5 )
Line 28     {
Line 29       if ( LODWORD(wimHeader->rhIntegrity.uncompressed_size) && !HIDWORD(wimHeader->rhIntegrity.uncompressed_size) )
Line 30       {
Line 31         uncompressSize = wimHeader->rhIntegrity.uncompressed_size;
Line 32         v17 = HIDWORD(v5) & 0xFFFFFF;
Line 33         v7 = GetProcessHeap();
Line 34         uncompressBuffer = HeapAlloc(v7, 8u, uncompressSize);
Line 35         v9 = uncompressBuffer;
Line 36         if ( uncompressBuffer && ReadIntegrityInfo((int)v1, (int)uncompressBuffer, nNumberOfBytesToWrite, v17) )
Line 37         {

All values in the wimHeader structure come from the file and are fully controlled by attacker. The most important fields in the above code in our proof of concept have the following values:

offset 0x7C : wimHeader->rhIntegrity.size_in_wim        = 0xFFF2
offset 0x8C : wimHeader->rhIntegrity.uncompressed_size  = 0x10

At line 34, we see a heap buffer allocation. Its size is based on the uncompressed_size field coming from rhIntegrity structure. There is no check whether size_in_wim is bigger than the uncompressed_size field which turns out to be crucial, because further inside ReadIntegrityInfo, the size_in_wim value indicates how many bytes should be read from file into the buffer allocated based on the uncompressed_size value.

KERNELBASE!ReadFile:
73d0e120 8bff            mov     edi,edi

0:000> kb
 # ChildEBP RetAddr  Args to Child              
00 0133f6fc 5003a803 0000004c 05f20ef0 0000fff2 KERNELBASE!ReadFile
01 0133f734 5003a906 0000fff2 0133f7b0 00000000 WIMGAPI!ReadWriteDataInternal+0x89
02 0133f78c 5004a8c7 0000fff2 0133f7b0 00000000 WIMGAPI!ReadWriteData+0x29
03 0133f7c8 5004a99e 0000fff2 00000000 00000000 WIMGAPI!ReadIntegrityInfo+0x55
04 0133f7f0 5002afeb 00000000 05f153d2 00000001 WIMGAPI!LoadIntegrityInfo+0x83
05 0133fa78 009611b6 05f1fd88 80000000 00000003 WIMGAPI!WIMCreateFile+0x52b
06 0133fd4c 00961eae 00000004 05f15398 05f15080 ConsoleApplication1!main+0x126 [t:\projects\bugs\wim\wimfuzzer\consoleapplication1\consoleapplication1\consoleapplication1.cpp @ 58] 
07 (Inline) -------- -------- -------- -------- ConsoleApplication1!invoke_main+0x1c [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 64] 
08 0133fd94 75018654 01100000 75018630 31652e02 ConsoleApplication1!__scrt_common_main_seh+0xf8 [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 259] 
09 0133fda8 76fc4a77 01100000 ff37efb2 00000000 KERNEL32!BaseThreadInitThunk+0x24
0a 0133fdf0 76fc4a47 ffffffff 76fe9ecb 00000000 ntdll!__RtlUserThreadStart+0x2f
0b 0133fe00 00000000 00961f24 01100000 00000000 ntdll!_RtlUserThreadStart+0x1b

0:000> dd esp+4 L3
0133f704  0000004c 05f20ef0 0000fff2

0:000> !heap -p -a 05f20ef0 
    address 05f20ef0 found in
    _HEAP @ 5f10000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        05f20ed8 0005 0000  [00]   05f20ef0    00010 - (busy)
        7702eeff ntdll!RtlpCallInterceptRoutine+0x00000026
        76fa16ee ntdll!RtlpAllocateHeapInternal+0x000002ee
        76fa13ee ntdll!RtlAllocateHeap+0x0000003e
        5004a989 WIMGAPI!LoadIntegrityInfo+0x0000006e
        5002afeb WIMGAPI!WIMCreateFile+0x0000052b
        9611b6 ConsoleApplication1!main+0x00000126
        961eae ConsoleApplication1!__scrt_common_main_seh+0x000000f8
        75018654 KERNEL32!BaseThreadInitThunk+0x00000024
        76fc4a77 ntdll!__RtlUserThreadStart+0x0000002f
        76fc4a47 ntdll!_RtlUserThreadStart+0x0000001b

This situation leads to a fully controllable heap corruption, and can be turned into remote code execution by an attacker.

Crash Information

0:000> !analyze -v
*******************************************************************************
*                                                                             *
*                        Exception Analysis                                   *
*                                                                             *
*******************************************************************************


DUMP_CLASS: 2

DUMP_QUALIFIER: 0

FAULTING_IP: 
ntdll!RtlReportCriticalFailure+4b
7703a83c cc              int     3

EXCEPTION_RECORD:  (.exr -1)
ExceptionAddress: 7703a83c (ntdll!RtlReportCriticalFailure+0x0000004b)
   ExceptionCode: 80000003 (Break instruction exception)
  ExceptionFlags: 00000000
NumberParameters: 1
   Parameter[0]: 00000000

FAULTING_THREAD:  000037b4

BUGCHECK_STR:  BREAKPOINT

DEFAULT_BUCKET_ID:  BREAKPOINT

PROCESS_NAME:  ConsoleApplication1.exe

ERROR_CODE: (NTSTATUS) 0x80000003 - {EXCEPTION}  Breakpoint  A breakpoint has been reached.

EXCEPTION_CODE: (HRESULT) 0x80000003 (2147483651) - One or more arguments are invalid

EXCEPTION_CODE_STR:  80000003

EXCEPTION_PARAMETER1:  00000000

WATSON_BKT_PROCSTAMP:  5aa26905

WATSON_BKT_MODULE:  ntdll.dll

WATSON_BKT_MODSTAMP:  3a21d961

WATSON_BKT_MODOFFSET:  da83c

WATSON_BKT_MODVER:  10.0.16299.248

MODULE_VER_PRODUCT:  Microsoft® Windows® Operating System

BUILD_VERSION_STRING:  10.0.16299.15 (WinBuild.160101.0800)

MODLIST_WITH_TSCHKSUM_HASH:  62c3758bb465dd1ebac418aeb1813920fdfc7979

MODLIST_SHA1_HASH:  7c46ba31abc7c4fa70952fbe7df4952f821ea5db

NTGLOBALFLAG:  1000

APPLICATION_VERIFIER_FLAGS:  0

PRODUCT_TYPE:  1

SUITE_MASK:  272

DUMP_TYPE:  fe

ANALYSIS_SESSION_HOST:  DESKTOP-E4N8506

ANALYSIS_SESSION_TIME:  03-12-2018 16:09:47.0701

ANALYSIS_VERSION: 10.0.15063.468 x86fre

THREAD_ATTRIBUTES: 
ADDITIONAL_DEBUG_TEXT:  Followup set based on attribute [Is_ChosenCrashFollowupThread] from Frame:[0] on thread:[PSEUDO_THREAD]

LAST_CONTROL_TRANSFER:  from 77042f99 to 7703a83c

THREAD_SHA1_HASH_MOD_FUNC:  4961d5f0ba58498cd49e530ee6493c971e9fbc17

THREAD_SHA1_HASH_MOD_FUNC_OFFSET:  3b2680676d69e292359230962719215aa4599dbf

OS_LOCALE:  ENU

PROBLEM_CLASSES: 

    ID:     [0n300]
    Type:   [@APPLICATION_FAULT_STRING]
    Class:  Primary
    Scope:  DEFAULT_BUCKET_ID (Failure Bucket ID prefix)
            BUCKET_ID
    Name:   Omit
    Data:   Add
            String: [BREAKPOINT]
    PID:    [Unspecified]
    TID:    [Unspecified]
    Frame:  [0]

PRIMARY_PROBLEM_CLASS:  BREAKPOINT

STACK_TEXT:  
00000000 00000000 heap_corruption!ConsoleApplication1.exe+0x0


THREAD_SHA1_HASH_MOD:  ca4e26064d24ef7512d2e94de5a93c38dbe82fe9

SYMBOL_STACK_INDEX:  0

SYMBOL_NAME:  heap_corruption!ConsoleApplication1.exe

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: heap_corruption

DEBUG_FLR_IMAGE_TIMESTAMP:  0

STACK_COMMAND:  !heap ; ** Pseudo Context ** ; kb

BUCKET_ID:  BREAKPOINT_heap_corruption!ConsoleApplication1.exe

FAILURE_EXCEPTION_CODE:  80000003

IMAGE_NAME:  heap_corruption

FAILURE_IMAGE_NAME:  heap_corruption

BUCKET_ID_IMAGE_STR:  heap_corruption

FAILURE_MODULE_NAME:  heap_corruption

BUCKET_ID_MODULE_STR:  heap_corruption

FAILURE_FUNCTION_NAME:  ConsoleApplication1.exe

BUCKET_ID_FUNCTION_STR:  ConsoleApplication1.exe

BUCKET_ID_OFFSET:  0

BUCKET_ID_MODTIMEDATESTAMP:  0

BUCKET_ID_MODCHECKSUM:  0

BUCKET_ID_MODVER_STR:  0.0.0.0

BUCKET_ID_PREFIX_STR:  BREAKPOINT_

FAILURE_PROBLEM_CLASS:  BREAKPOINT

FAILURE_SYMBOL_NAME:  heap_corruption!ConsoleApplication1.exe

FAILURE_BUCKET_ID:  BREAKPOINT_80000003_heap_corruption!ConsoleApplication1.exe

TARGET_TIME:  2018-03-12T15:09:50.000Z

OSBUILD:  16299

OSSERVICEPACK:  15

SERVICEPACK_NUMBER: 0

OS_REVISION: 0

OSPLATFORM_TYPE:  x86

OSNAME:  Windows 10

OSEDITION:  Windows 10 WinNt SingleUserTS

USER_LCID:  0

OSBUILD_TIMESTAMP:  2031-10-27 03:56:14

BUILDDATESTAMP_STR:  160101.0800

BUILDLAB_STR:  WinBuild

BUILDOSVER_STR:  10.0.16299.15

ANALYSIS_SESSION_ELAPSED_TIME:  a3b

ANALYSIS_SOURCE:  UM

FAILURE_ID_HASH_STRING:  um:breakpoint_80000003_heap_corruption!consoleapplication1.exe

FAILURE_ID_HASH:  {b2af3544-b437-1ecc-b8b1-827e2423f9a0}

Followup:     MachineOwner
---------

Timeline

2018-03-27 - Vendor Disclosure
2018-06-12 - Public Release

Credit

Discovered by Marcin 'Icewall' Noga of Cisco Talos.