FortiGuard Labs Threat Research

Microsoft Kernel Integer Overflow Vulnerability

By Honggang Ren | October 31, 2016

Last month I discovered and reported an integer overflow vulnerability in the Windows Registry. Last Tuesday, October 25th, Microsoft released Security Bulletin MS16-124, which contains the patch for this vulnerability, and identifies it as CVE-2016-0070.

This vulnerability could lead to local privilege elevation, and is rated as “Important” by Microsoft. The vulnerability affects multiple Windows versions, and Microsoft has recommended installing this update immediately.

In this blog I will share the details of this vulnerability.

How to Reproduce

To reproduce the vulnerability, follow the steps below.

  1. Sign into Windows 7 with any non-admin account.
  2. Run regedit.exe in Command Prompt to open Registry Editor.
  3. Choose "HKEY_USERS" from the left pane of Registry Editor.
  4. Click menu item "File" => "Load Hive".
  5. Choose the PoC file PoC.hiv and open it.
  6. In the popup dialog, input any characters in "Key Name" such as "ddd".
  7. You will see the Windows 7 Bugcheck blue screen error, as shown in Figure 1.

Figure 1 – Bugcheck Blue Screen

Analysis

This vulnerability is triggered when parsing the crafted file PoC.hiv. So let’s take a look at it first. The screenshot in Figure 2 shows the key file structure of PoC.hiv.

Figure 2 - File Structure of PoC.hiv

As highlighted in the screenshot above, the integer overflow is caused by the crafted value 0x80000001 of ValueCount in the struct NKCELL.

Based on my analysis, the vulnerability exists in the function “CmpCheckKey”. Following is the code snippet of this function.

PAGE:82C10E9B ; int __thiscall CmpCheckKey(int, char, int, int, ULONG_PTR BugCheckParameter3, PRTL_BITMAP BitMapHeader)

PAGE:82C10E9B _CmpCheckKey@24 proc near 

...

PAGE:82C114C0 loc_82C114C0:     ; CODE XREF: CmpCheckKey(x,x,x,x,x,x)+60Fj

PAGE:82C114C0       mov     edx, [ebp+var_14] ; The value of edx is got from the PoC at offset 0x1048 and its value is 0x80000001.

PAGE:82C114C3       shl     edx, 2 ; edx is multiplied by 4. This results in integer overflow and the value of edx becomes 4.

PAGE:82C114C6       cmp     edx, 4

PAGE:82C114C9       jb      short loc_82C11512 ;  The comparison result is false.

PAGE:82C114CB       mov     ecx, [ebp+BugCheckParameter3]

PAGE:82C114CE       mov     eax, esi

PAGE:82C114D0       call    _HvGetCellSize@8 ; HvGetCellSize(x,x)

PAGE:82C114D5       cmp     edx, eax ;  Compare eax=0xc with edx=4.

PAGE:82C114D7       ja      short loc_82C11512 ;  The comparison result is false.

PAGE:82C114D9       lea     eax, [ebp+var_C]

PAGE:82C114DC       push    eax

PAGE:82C114DD       push    [ebp+arg_4]

PAGE:82C114E0       mov     al, [edi+2]

PAGE:82C114E3       push    [ebp+var_14] ; The crafted ValueCount value 0x80000001 is pushed on stack.

PAGE:82C114E6       shr     al, 4

PAGE:82C114E9       and     al, 1

PAGE:82C114EB       push    ecx

PAGE:82C114EC       mov     ecx, [ebp+BitMapHeader]

PAGE:82C114EF       movzx   eax, al

PAGE:82C114F2       push    eax

PAGE:82C114F3       push    esi

PAGE:82C114F4       lea     edx, [ebp+var_10]

PAGE:82C114F7       call    _CmpCheckValueList@32 ; Call this function which causes Windows kernel bugcheck.

PAGE:82C114FC       test    eax, eax       

Following is the code snippet of the function “_CmpCheckValueList@32”.

PAGE:82C11F24 ; __stdcall CmpCheckValueList(x, x, x, x, x, x, x, x)

PAGE:82C11F24 _CmpCheckValueList@32 proc near 

...

PAGE:82C17253 loc_82C17253:   ; CODE XREF: CmpCheckValueList(x,x,x,x,x,x,x,x)+32Bj

PAGE:82C17253       mov     ecx, [ebp+var_44]

PAGE:82C17256       cmp     [ecx], eax

PAGE:82C17258       jnb     short loc_82C1725C

PAGE:82C1725A       mov     [ecx], eax

PAGE:82C1725C

PAGE:82C1725C loc_82C1725C:    ; CODE XREF: CmpCheckValueList(x,x,x,x,x,x,x,x)+334j

PAGE:82C1725C       inc     [ebp+var_20] ;  The value of [ebp+var_20] becomes 1 in the 1st iteration of the loop.

PAGE:82C1725F       add     [ebp+var_38], 4

PAGE:82C17263       jmp     loc_82C16F89 ;  Jump to the 2nd iteration of the loop.

...

PAGE:82C173FF loc_82C173FF:   ; CODE XREF: CmpCheckValueList(x,x,x,x,x,x,x,x)+4D3j

PAGE:82C173FF       push    0

PAGE:82C17401       push    [ebp+arg_10]

PAGE:82C17404       mov     eax, esi

PAGE:82C17406       call    _HvMarkCellDirty@12 ; HvMarkCellDirty(x,x,x)

PAGE:82C1740B       test    al, al

PAGE:82C1740D       jz      loc_82C175B8

PAGE:82C17413       push    0

PAGE:82C17415       push    dword ptr [edi+28h]

PAGE:82C17418       mov     eax, esi

PAGE:82C1741A       call    _HvMarkCellDirty@12 ; HvMarkCellDirty(x,x,x)

PAGE:82C1741F       test    al, al

PAGE:82C17421       jz      loc_82C175B8

PAGE:82C17427       dec     dword ptr [edi+24h]

PAGE:82C1742A       dec     [ebp+arg_C] ; [ebp+arg_C] is 0x80000001 which is a parameter passed by caller. Here it decreases 1.

PAGE:82C1742D       mov     eax, [ebp+arg_C]

PAGE:82C17430       sub     eax, [ebp+var_20] ; [ebp+var_20] is 1 which is got from the 1st iteration of the above loop. Subtract 1 from 0x80000000, the result is 0x7fffffff.

PAGE:82C17433       shl     eax, 2 ;  eax is multiplied by 4, the result is eax = 0xfffffffc.

PAGE:82C17436       push    eax ;  A crafted memcpy size 0xfffffffc is pushed on stack.

PAGE:82C17437       mov     eax, [ebp+var_38]

PAGE:82C1743A       lea     ecx, [eax+4]

PAGE:82C1743D       push    ecx             ; void *

PAGE:82C1743E       push    eax             ; void *

PAGE:82C1743F       call    _memmove ;  Call this function which results in the heap overflow.

PAGE:82C17444       mov     esi, [esi+28h]

...

 

Following is the code snippet of the function “_memmove”.

...

.text:82A7C6AB       and     edx, 3

.text:82A7C6AE       cmp     ecx, 8          ; switch 8 cases

.text:82A7C6B1       jb      short loc_82A7C6DC ;

.text:82A7C6B3       rep movsd  ;  Heap overflow occurs here due to the large copy size.

.text:82A7C6B5       jmp     ds:off_82A7C7CC[edx*4]

...

In summary, this vulnerability is triggered by an integer overflow that results in a heap overflow when performing a memory copy operation. Successful exploitation of this vulnerability could lead to local privilege elevation.