flawopen.com/Teardowns/cve-2024-30051-windows-dwm-privilege-escalation
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.
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é.
Desktop Window Manager (dwmcore.dll)Integer Wrap-Around / OverflowPool / Heap CorruptionSafe Integer Arithmetic (ULongAdd)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.
Un processus local sans privilèges (comme un dropper QakBot) initialise un canal IPC avec le Desktop Window Manager.
L'attaquant conçoit un message DirectComposition où la somme de offset et length dépasse délibérément 0xFFFFFFFF.
Le fichier dwmcore.dll non corrigé calcule la somme tronquée et alloue un bloc de 16 octets au lieu de plusieurs mégaoctets.
Le parseur copie la charge utile dans ce micro-tampon, écrasant les pointeurs de fonction voisins pour obtenir les privilèges 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;
}