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

● CVE-2024-30051 · CVSS 9.8 · Critique
Recherche · FlawOpen

CVE-2024-30051: Analyse du débordement de tas dans Windows DWM Core Library

Comment une addition d'entiers 32 bits non vérifiée dans dwmcore.dll a permis à un logiciel malveillant local de déclencher une allocation de tas sous-dimensionnée, de corrompre la mémoire et d'obtenir les privilèges SYSTEM.

💡 Explication en Langage Simple (ELI5)

Imaginez qu'une entreprise de livraison vous fournisse un carton miniature pour 10 objets parce que vous avez déclaré '5 objets plus 5 objets'. Mais vous transmettez des chiffres tellement démesurés que le compteur informatique dépasse sa capacité et retombe à zéro: il calcule que '4 milliards plus 10 objets égalent 10 objets'. Il prépare une minuscule boîte, vous y forcez 4 milliards d'objets qui débordent dans tout l'entrepôt, vous permettant ainsi de prendre le contrôle du centre de sécurité.

Concepts Clés et Termes

Desktop Window Manager (dwmcore.dll)
Sous-système clé de Windows chargé de la composition visuelle des fenêtres, du rendu DirectComposition et des graphismes du bureau.
Integer Wrap-Around / Overflow
En arithmétique 32 bits non signée, 0xFFFFFFFF + 1 repasse à 0. Effectué avant d'allouer la mémoire, cela crée un tampon excessivement petit.
Pool / Heap Corruption
Écriture de données au-delà des limites d'un bloc de tas dans les structures adjacentes, permettant une élévation de privilèges vers NT AUTHORITY\SYSTEM.
Safe Integer Arithmetic (ULongAdd)
Bibliothèque arithmétique sécurisée de Microsoft vérifiant si une addition dépasse les limites avant de retourner la somme.

Analyse de Cause Racine

La cause réside dans un dépassement d'entier 32 bits non contrôlé dans dwmcore.dll!CInteraction::ProcessInputArray, où l'addition offset + count boucle à zéro, allouant un tampon de 16 octets débordé ensuite par memcpy.

Déroulement de l'Attaque Étape par Étape

Step 1

1. Exécution initiale du malware

Un processus local sans privilèges (comme un dropper QakBot) initialise un canal IPC avec le Desktop Window Manager.

Step 2

2. Conception de la commande volumineuse

L'attaquant conçoit un message DirectComposition où la somme de offset et length dépasse délibérément 0xFFFFFFFF.

Step 3

3. Allocation sous-dimensionnée du tas

Le fichier dwmcore.dll non corrigé calcule la somme tronquée et alloue un bloc de 16 octets au lieu de plusieurs mégaoctets.

Step 4

4. Écriture en mémoire et élévation SYSTEM

Le parseur copie la charge utile dans ce micro-tampon, écrasant les pointeurs de fonction voisins pour obtenir les privilèges SYSTEM.

Code Source : Vulnérable vs Sécurisé

✕ IMPLÉMENTATION VULNÉRABLE
// 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;
}
✓ PATCH SÉCURISÉ ET ROBUSTE
// 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;
}

Liste de Contrôle de Sécurité pour l'Ingénierie