flawopen.com/Teardowns/cve-2024-30051-windows-dwm-privilege-escalation
Cómo una suma de enteros de 32 bits no validada en dwmcore.dll permitió al malware local provocar una asignación de memoria insuficiente en el montón, corromper la memoria y escalar a privilegios SYSTEM.
Imagina que una empresa de paquetería te entrega una caja pequeña para 10 artículos porque declaraste 'tengo 5 artículos más 5 artículos'. Pero envías números tan desmesurados que el sumador del ordenador vuelve a cero: la máquina calcula que '4 mil millones más 10 artículos equivalen a 10 artículos'. Se prepara una caja diminuta, empujas 4 mil millones de paquetes, estos desbordan el almacén y te permiten tomar el control de toda la instalación de seguridad.
Desktop Window Manager (dwmcore.dll)Integer Wrap-Around / OverflowPool / Heap CorruptionSafe Integer Arithmetic (ULongAdd)La causa fundamental radica en un desbordamiento de enteros de 32 bits en dwmcore.dll!CInteraction::ProcessInputArray, donde la suma offset + count supera 0xFFFFFFFF, asignando un búfer de solo 16 bytes que luego se desborda con memcpy.
Un proceso de malware con bajos privilegios (como el dropper QakBot) inicializa un canal IPC con Desktop Window Manager.
El atacante crea un mensaje de dibujo DirectComposition donde offset + length supera deliberadamente 0xFFFFFFFF.
La biblioteca dwmcore.dll sin parchear calcula la suma truncada y asigna un fragmento de solo 16 bytes en lugar de varios megabytes.
El analizador copia la carga completa en el pequeño búfer, sobrescribiendo punteros de función adyacentes para obtener privilegios 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;
}