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

● CVE-2024-30051 · CVSS 9.8 · Crítica
Investigación · FlawOpen

CVE-2024-30051: Análisis del desbordamiento de búfer en Windows DWM Core Library

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.

💡 Explicación en Lenguaje Sencillo (ELI5)

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.

Conceptos Clave y Términos

Desktop Window Manager (dwmcore.dll)
Subsistema esencial de Windows encargado de la composición visual de ventanas, el renderizado de DirectComposition y los gráficos del escritorio.
Integer Wrap-Around / Overflow
En aritmética sin signo de 32 bits, 0xFFFFFFFF + 1 vuelve a 0. Si se calcula antes de asignar memoria, se crea un búfer mucho más pequeño del necesario.
Pool / Heap Corruption
Escritura de datos más allá del límite de un fragmento de montón en estructuras adyacentes del asignador, permitiendo la escalada local a NT AUTHORITY\SYSTEM.
Safe Integer Arithmetic (ULongAdd)
Biblioteca aritmética segura de Microsoft que comprueba si una suma produce desbordamiento antes de devolver el resultado.

Análisis de Causa Raíz

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.

Flujo de Ataque Paso a Paso

Step 1

1. Ejecución del malware local

Un proceso de malware con bajos privilegios (como el dropper QakBot) inicializa un canal IPC con Desktop Window Manager.

Step 2

2. Creación de comando sobredimensionado

El atacante crea un mensaje de dibujo DirectComposition donde offset + length supera deliberadamente 0xFFFFFFFF.

Step 3

3. Asignación de montón de tamaño insuficiente

La biblioteca dwmcore.dll sin parchear calcula la suma truncada y asigna un fragmento de solo 16 bytes en lugar de varios megabytes.

Step 4

4. Sobrescritura lineal de memoria y escalada a SYSTEM

El analizador copia la carga completa en el pequeño búfer, sobrescribiendo punteros de función adyacentes para obtener privilegios SYSTEM.

Código Fuente: Vulnerable vs. Seguro

✕ IMPLEMENTACIÓN VULNERABLE
// 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;
}
✓ PARCHE SEGURO Y ROBUSTO
// 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;
}

Lista de Verificación de Seguridad para Ingeniería