CVE-2024-30051 / Patch Tuesday Zero-Day

CVE-2024-30051: Windows DWM Core Library Heap Overflow Teardown

How an unchecked 32-bit integer addition in dwmcore.dll allowed local malware to trigger an undersized heap allocation, corrupt memory, and escalate to SYSTEM privileges.

💡 Plain English Explainer (ELI5)

Imagine a shipping company gives you a small box that holds 10 items because you told them 'I have 5 items plus 5 items'. But you cleverly pass numbers so big that the computer's simple addition wraps around back to zero—telling the computer '4 billion plus 10 items equals 10 items'. The computer prepares a tiny box, you shove in 4 billion items, and it spills all over the warehouse floor, letting you take control of the entire facility.

Core Concepts & Subsystem Terms

Desktop Window Manager (dwmcore.dll)
The core Windows subsystem responsible for compositing visual window frames, direct composition rendering, and desktop graphics.
Integer Wrap-Around / Overflow
In 32-bit unsigned arithmetic, `0xFFFFFFFF + 1` wraps around to `0`. If calculated before allocating a heap buffer, an undersized buffer is created.
Pool / Heap Corruption
Writing data past the boundary of a heap chunk into neighboring allocator structures, enabling local privilege escalation to `NT AUTHORITY\SYSTEM`.
Safe Integer Arithmetic (`ULongAdd`)
Microsoft's safe runtime arithmetic library that verifies whether an addition overflows before returning the sum.

Step-by-Step Exploit Mechanics

Step 1

1. Initial Access Execution

A low-privileged local malware process (e.g. QakBot dropper) initializes an IPC channel with the Desktop Window Manager.

Step 2

2. Crafting Oversized Command

The attacker crafts a direct composition drawing message where commandHeader.offset + commandHeader.length deliberately wraps past 0xFFFFFFFF.

Step 3

3. Undersized Heap Allocation

The unpatched dwmcore.dll computes the wrapped sum, allocating a 64-byte heap chunk instead of several megabytes.

Step 4

4. Linear Memory Overwrite & SYSTEM Escalation

The message parser copies the entire payload into the tiny heap chunk, overwriting adjacent function pointers to achieve full system privileges.

Source Code: Fatal Flaw vs. High-Level Fix

Delivered in clean, readable high-level source code (no raw assembly or binary diffs).

UNPATCHED FLAW
// 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;
}
HARDENED PATCH
// 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;
}

Engineering & System Hardening Checklist

← Browse Full Security Directory Explore All Source Teardowns →