CVE-2018-8120 漏洞分析及利用

作者:b2ahex

1. 背景介绍

An elevation of privilege vulnerability exists in Windows when the Win32k component fails to properly handle objects in memory. An attacker who successfully exploited this vulnerability could run arbitrary code in kernel mode. An attacker could then install programs; view, change, or delete data; or create new accounts with full user rights.
To exploit this vulnerability, an attacker would first have to log on to the system. An attacker could then run a specially crafted application that could exploit the vulnerability and take control of an affected system.
The update addresses this vulnerability by correcting how Win32k handles objects in memory.

漏洞原因是在 win32k!SetImeInfoEx 中没有对指针进行验证就直接使用,当指针指向0地址时,系统可能会引用用户层可控的数据,实现任意地址写到任意代码执行的功能。

2. 漏洞分析

对比 kb4103712 补丁前后 win32k.sys 文件,在 win32k!SetImeInfoEx 中增加对指针是否为0的验证。

补丁前:

.text:BF810067                 push    ebp
.text:BF810068                 mov     ebp, esp
.text:BF81006A                 mov     eax, [ebp+atagWINDOWStation]
.text:BF81006D                 test    eax, eax
.text:BF81006F                 jz      short loc_BF81008B
.text:BF810071                 mov     ecx, [eax+14h]    ;没有检查ecx,如果下面条件判断成功会跳到loc_BF81008F,执行rep movsd
.text:BF810074                 push    esi
.text:BF810075                 mov     esi, [ebp+r3buf]
.text:BF810078                 mov     edx, [esi]
.text:BF81007A                 mov     eax, ecx
.text:BF81007C
.text:BF81007C loc_BF81007C:                           ; CODE XREF: SetImeInfoEx(x,x)+21j
.text:BF81007C                 cmp     [eax+14h], edx
.text:BF81007F                 jz      short loc_BF81008F 
.text:BF81007F                                         
.text:BF810081                 mov     eax, [eax+8]
.text:BF810084                 cmp     eax, ecx
.text:BF810086                 jnz     short loc_BF81007C
.text:BF810088
.text:BF810088 loc_BF810088:                           ; CODE XREF: SetImeInfoEx(x,x)+2Fj
.text:BF810088                 xor     eax, eax
.text:BF81008A
.text:BF81008A loc_BF81008A:                           ; CODE XREF: SetImeInfoEx(x,x)+43j
.text:BF81008A                 pop     esi
.text:BF81008B
.text:BF81008B loc_BF81008B:                           ; CODE XREF: SetImeInfoEx(x,x)+Aj
.text:BF81008B                 pop     ebp
.text:BF81008C                 retn    8
.text:BF81008F ; ---------------------------------------------------------------------------
.text:BF81008F
.text:BF81008F loc_BF81008F:                           ; CODE XREF: SetImeInfoEx(x,x)+1Aj
.text:BF81008F                 mov     eax, [eax+2Ch]  
.text:BF81008F                                         
.text:BF810092                 test    eax, eax
.text:BF810094                 jz      short loc_BF810088
.text:BF810096                 cmp     dword ptr [eax+48h], 0 
.text:BF81009A                 jnz     short loc_BF8100A5 
.text:BF81009C                 push    edi             
.text:BF81009D                 push    57h
.text:BF81009F                 pop     ecx
.text:BF8100A0                 mov     edi, eax
.text:BF8100A2                 rep movsd
.text:BF8100A4                 pop     edi
.text:BF8100A5
.text:BF8100A5 loc_BF8100A5:                           ; CODE XREF: SetImeInfoEx(x,x)+35j
.text:BF8100A5                 xor     eax, eax        
.text:BF8100A7                 inc     eax

补丁后:

.text:BF810A96                 push    ebp
.text:BF810A97                 mov     ebp, esp
.text:BF810A99                 mov     eax, [ebp+arg_0]
.text:BF810A9C                 test    eax, eax
.text:BF810A9E                 jnz     short loc_BF810AA4
.text:BF810AA0
.text:BF810AA0 loc_BF810AA0:                           ; CODE XREF: SetImeInfoEx(x,x)+15j
.text:BF810AA0                 xor     eax, eax
.text:BF810AA2                 jmp     short loc_BF810AC2
.text:BF810AA4 ; ---------------------------------------------------------------------------
.text:BF810AA4
.text:BF810AA4 loc_BF810AA4:                           ; CODE XREF: SetImeInfoEx(x,x)+Aj
.text:BF810AA4                 mov     edx, [eax+14h]
.text:BF810AA7                 test    edx, edx            ;判断edx是否为0
.text:BF810AA9                 jz      short loc_BF810AA0
.text:BF810AAB                 push    esi
.text:BF810AAC                 mov     esi, [ebp+arg_4]
.text:BF810AAF                 mov     ecx, [esi]
.text:BF810AB1                 mov     eax, edx
.text:BF810AB3
.text:BF810AB3 loc_BF810AB3:                           ; CODE XREF: SetImeInfoEx(x,x)+29j
.text:BF810AB3                 cmp     [eax+14h], ecx
.text:BF810AB6                 jz      short loc_BF810AC6
.text:BF810AB8                 mov     eax, [eax+8]
.text:BF810ABB                 cmp     eax, edx
.text:BF810ABD                 jnz     short loc_BF810AB3

没有对 spklList 进行验证,下面访问该指针成员 piiex (+0x2c),如果 spklList 为0,在未开启零页保护的系统下可以通过 NtAllocateVirtualMemory 申请0地址内存,此时+0x2c的指针数据是可控的:

如果该指针+0x48处为0,代码会执行memcpy操作:

目的地址是由0x2c处的指针决定的,源地址来自参数,查看上一层 NtUserSetImeInfoEx v6经过一次memcpy,源数据来自用户层参数:

3. 生成POC

满足 win32k!NtUserSetImeInfoExwin32k!SetImeInfoEx 中执行memcpy的几个条件后构造代码如下:

memcpy前:

memcpy后:

4. 漏洞利用

由于漏洞可以实现任意地址写,可以利用Pool Spraying布置内存,通过 NtAllocateReserveObject 申请大量IOCO对象,由于漏洞会写入的buf长度是0x15c字节,所以free间隔4个对象的长度,通过 NtQuerySystemInformation 泄露出其中一个紧挨着free内存的IOCO对象,从free内存开始写直到覆盖TypeIndex部分,参考,计算要复制的缓存区起点位置 = [该对象地址 - 0xC - 15b], -0xC 处是 TypeIndex )

nt!_OBJECT_HEADER
   +0x000 PointerCount     : Int4B
   +0x004 HandleCount      : Int4B
   +0x004 NextToFree       : Ptr32 Void
   +0x008 Lock             : _EX_PUSH_LOCK
   +0x00c TypeIndex        : UChar
   +0x00d TraceFlags       : UChar
   +0x00e InfoMask         : UChar
   +0x00f Flags            : UChar
   +0x010 ObjectCreateInfo : Ptr32 _OBJECT_CREATE_INFORMATION
   +0x010 QuotaBlockCharged : Ptr32 Void
   +0x014 SecurityDescriptor : Ptr32 Void
   +0x018 Body             : _QUAD

用户层构造buf时注意构造最后0x23个字节的数据,将 TypeIndex 0x0a修改为0,使 CloseProcedure 指向0x60,我们在此处设置shellcode指针,为了保证漏洞正常触发,确保内核地址+0x48处等于0:

将内存布置为理想的状态后,触发漏洞,检查源缓冲区和目标缓冲区:

最终通过调用 CloseHandle 执行 shellcode ,替换 system token 达到提权的效果

多试几次 :)