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)

運送会社の窓口で『荷物は5個と5個です』と言って10個入る小さな箱をもらう場面を想像してください。しかし、計算機が42億を超えるとゼロに戻る仕組みを悪用し、『40億個+10個=10個』と認識させます。窓口は小さな箱を渡しますが、そこに40億個の荷物を無理やり詰め込むことで倉庫中に荷物が溢れかえり、最終的に施設全体の管理権を奪うようなものです。

主要な概念と専門用語

Desktop Window Manager (dwmcore.dll)
ウィンドウ枠の合成、DirectComposition の描画、デスクトップグラフィックス全般を担当する Windows の中核サブシステム。
Integer Wrap-Around / Overflow
32ビット符号なし整数では 0xFFFFFFFF + 1 が 0 に巻き戻ります。ヒープ確保前にこの計算が行われると、極小サイズのバッファが作成されます。
Pool / Heap Corruption
ヒープチャンクの境界を越えて隣接するメモリアロケータ構造体を破壊し、NT AUTHORITY\SYSTEM 権限への昇格を可能にする脆弱性。
Safe Integer Arithmetic (ULongAdd)
加算がオーバーフローするかどうかを検証してから結果を返す、Microsoft の安全な整数演算ランタイムライブラリ。

根本原因の分析 (Root Cause)

根本原因は dwmcore.dll 内の CInteraction::ProcessInputArray における未検証の32ビット整数オーバーフローです。offset + count が 0xFFFFFFFF を超えてラップアラウンドし、極小のヒープが割り当てられた後に memcpy による境界外書き込みが発生しました。

ステップ・バイ・ステップの攻撃フロー

Step 1

1. 低権限プロセスによる IPC 接続

低権限のマルウェア(QakBot ドロッパーなど)がデスクトップウィンドウマネージャーと IPC 接続を初期化します。

Step 2

2. 意図的にラップアラウンドするコマンドの生成

攻撃者は commandHeader.offset + length が 0xFFFFFFFF を超過するよう設計した DirectComposition メッセージを構築します。

Step 3

3. 過小なヒープバッファの確保

パッチ適用前の dwmcore.dll がオーバーフローした小さな値で計算を行い、メガバイト単位ではなくわずか16バイトのヒープを確保します。

Step 4

4. メモリ破壊と SYSTEM 権限への昇格

メッセージパーサーが大量のペイロードをその微小な領域へコピーし、隣接する関数ポインタを上書きして SYSTEM 権限を奪取します。

ソースコード比較:脆弱 vs 堅牢化

✕ 脆弱な実装
// 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;
}

エンジニアリング&システム堅牢化チェックリスト