flawopen.com/Teardowns/cve-2024-30051-windows-dwm-privilege-escalation

● CVE-2024-30051 · CVSS 9.8 · 严重
安全研究 · FlawOpen

CVE-2024-30051: Windows DWM 核心库堆溢出提权技术拆解

深入剖析 dwmcore.dll 中未校验的 32 位整数加法如何导致堆缓冲区分配过小,从而引发内存破坏并最终提权至 SYSTEM 权限。

💡 通俗易懂的原理解析 (ELI5)

想象一家物流仓库根据你的申报单给你准备了一个只能放 10 件货物的超小纸箱,因为你填报了‘5 件加 5 件’。然而你故意利用了计数器在 42 亿时溢出归零的规则,谎报‘40 亿加 10 件等于 10 件’。仓库准备了小盒子,你却强行推进 40 亿件货物,堆满并冲垮了整个仓库过道,进而控制了整个工厂的安防系统。

核心概念与专有名词

Desktop Window Manager (dwmcore.dll)
Windows 核心桌面窗口管理器子系统,负责窗口视觉合成、DirectComposition 渲染及桌面图形流水线。
Integer Wrap-Around / Overflow
在 32 位无符号整数中,0xFFFFFFFF + 1 会溢出回绕为 0。如果在分配堆内存前进行此类计算,会导致分配出极小的缓冲区。
Pool / Heap Corruption
向堆块边界之外写入数据破坏邻近的分配器元数据结构,可实现本地权限提升至 NT AUTHORITY\SYSTEM。
Safe Integer Arithmetic (ULongAdd)
微软提供的安全运行时算术库,在返回计算和前严格验证加法是否会发生溢出。

根本原因剖析 (Root Cause)

根本原因在于 dwmcore.dll 的 CInteraction::ProcessInputArray 函数中存在未经检查的 32 位整数溢出,offset + count 发生回绕后导致仅分配 16 字节堆内存,随后由 memcpy 引发严重堆溢出。

攻击执行流程分解

Step 1

1. 初始本地访问与 IPC 建立

低权限本地恶意进程(如 QakBot 木马投放器)与 Desktop Window Manager 建立 IPC 管道连接。

Step 2

2. 构造超长合成绘图指令

攻击者精心构造 DirectComposition 绘图指令,使 commandHeader.offset 与 length 之和恰好跨越 0xFFFFFFFF 边界。

Step 3

3. 触发极小堆块分配

未打补丁的 dwmcore.dll 执行未保护加法,计算出极小数值,分配了一个仅 16 字节的微型堆缓冲区。

Step 4

4. 线性覆盖堆内存并接管 SYSTEM 权限

消息解析器将大量载荷数据 memcpy 拷入该微型堆块,线性溢出并覆盖邻近函数指针,最终获得 SYSTEM 权限。

源代码对比:漏洞与安全实现

✕ 存在漏洞的实现
// VULNERABLE: Decompiled C logic from dwmcore.dll before May 2024 patch
HRESULT CInteraction::ProcessInputArray(BYTE* pBuffer, ULONG offset, ULONG count) {
    // CRITICAL ROOT CAUSE:
    // Raw addition wraps around 32-bit integer boundaries!
    // If offset = 0xFFFFFFF0 and count = 0x20:
    // 0xFFFFFFF0 + 0x20 = 0x00000010 (16 bytes!)
    ULONG totalAllocationSize = offset + count;

    // Allocates a tiny 16-byte heap buffer!
    BYTE* pDestArray = (BYTE*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, totalAllocationSize);
    if (!pDestArray) {
        return E_OUTOFMEMORY;
    }

    // Copies original oversized byte count, overflowing heap chunks!
    memcpy(pDestArray + offset, pBuffer, count);
    return S_OK;
}
✓ 加固后的安全修复
// SECURE: Decompiled C logic from dwmcore.dll after Patch Tuesday
#include <intsafe.h>

HRESULT CInteraction::ProcessInputArray(BYTE* pBuffer, ULONG offset, ULONG count) {
    ULONG totalAllocationSize = 0;

    // 1. Enforce safe integer arithmetic check
    // Returns INTSAFE_E_ARITHMETIC_OVERFLOW if sum exceeds ULONG_MAX
    if (FAILED(ULongAdd(offset, count, &totalAllocationSize))) {
        return E_INVALIDARG;
    }

    // 2. Validate upper bound threshold limits
    if (totalAllocationSize > MAX_ALLOWED_INPUT_SIZE) {
        return E_INVALIDARG;
    }

    BYTE* pDestArray = (BYTE*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, totalAllocationSize);
    if (!pDestArray) {
        return E_OUTOFMEMORY;
    }

    memcpy(pDestArray + offset, pBuffer, count);
    return S_OK;
}

工程与系统安全加固清单