CVE-2018-8210
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.
WIMGAPI 10.0.16299.15 (WinBuild.160101.0800)
8.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
CWE-122: Heap-based Buffer Overflow
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.
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
---------
2018-03-27 - Vendor Disclosure
2018-06-12 - Public Release
Discovered by Marcin 'Icewall' Noga of Cisco Talos.