
Análisis técnico detallado y exploit de prueba de concepto para CVE-2024-30051, un desbordamiento de búfer basado en el montón en la biblioteca principal DWM de Windows que permite la escalada de privilegios local al nivel de Sistema de Integridad.
En esta publicación de blog, explicaré una vulnerabilidad en la biblioteca principal DWM de Microsoft Windows que analicé cuando se desarrollaba el exploit para Core Impact. Permite que un atacante sin privilegios ejecute código como usuario DWM con privilegios de Integridad del Sistema (CVE-2024-30051).
Dado que en ese momento no había suficiente información pública para desarrollar el exploit, tuve que realizar mucha ingeniería inversa, por lo que aquí mostraré cómo aplicar ingeniería inversa al parche KB5037771 para Windows 23H2 usando IDA PRO. Usaré BINDIFF para realizar la comparación binaria entre dwmcore.dll versión 10.0.22621.3447 y la versión 10.0.22621.3593, mostraré cómo se produce el desbordamiento del montón y luego lo explotaré elevando privilegios, y finalmente crearé un PoC funcional.
Índice:
Detalles de la vulnerabilidad: [2]
Diffing para encontrar el error: [3]
Análisis del PoC que explota CVE-2024-30051: [8]
3) Creación de la ventana [16]
4) Creación del dispositivo [16]
5) Creación de la fábrica [22]
6) Creación del contexto del dispositivo [28]
7) Creación del dispositivo de composición [29]
8) Llamada a la función hook3 [31]
9) Creación del objetivo para HWND [32]
10) Creación de la superficie [33]
11) Llamada a BeginDraw, EndDraw y CreateVisual [34]
11) Llamada a Visual SetContent [36]
12) Liberación de objetos [38]
13) Confirmación del dispositivo de composición [38]
17) Realización de Heap Spray [49]
18) Modificación del chunk base antes del envío [51]
19) Depuración del proceso DWM [52]
20) Elevación de privilegios al nivel de Integridad del Sistema [62]
Vulnerabilidad de Elevación de Privilegios en la Biblioteca Principal DWM de Windows CVE-2024-30051
Publicado: 14 de mayo de 2024
CNA asignador: Microsoft CVE-2024-30051
Impacto: Elevación de Privilegios
Severidad máxima: Importante
Debilidad:
CWE-122: Desbordamiento de búfer basado en montón
CVSS: 3.1 7.8 / 7.2
La vulnerabilidad existe debido a un error de cálculo de tamaño en una división entera dentro de la biblioteca principal DWM de Windows llamada dwmcore.dll. Un usuario local puede provocar un desbordamiento de búfer en el montón en el método CCommandBuffer::Initialize en dwmcore.dll y puede ejecutar código arbitrario con el usuario DWM con privilegios de Integridad del Sistema. El exploit realizará un Heap Spray en el proceso DWM para preparar la memoria y finalmente produce un desbordamiento de montón en dwmcore.dll que se activará al liberar ciertas partes del heap spray.
Una vez que el exploit tiene éxito, el proceso DWM cargará nuestra DLL manipulada que ejecuta nuestro código o nuestro ejecutable (en nuestro caso un CMD) como el usuario DWM que tiene privilegios de Integridad del Sistema.

Recorramos esta vulnerabilidad y veamos cómo nos permite ejecutarnos como un usuario DWM con Nivel de Integridad SYSTEM. Tenga en cuenta que, dado que no es un usuario que pertenezca al grupo Administradores, tiene algunas restricciones de privilegios.
El parche para Windows 11 23H2 se puede descargar desde:
https://www.catalog.update.microsoft.com/Search.aspx?q=KB5037771
windows11.0-kb5037771-x64_19a3f100fb8437d059d7ee2b879fe8e48a1bae42.msu
La versión vulnerable de dwmcore.dll es: 10.0.22621.3447
La versión parcheada de dwmcore.dll es: 10.0.22621.3593
Analizando las funciones modificadas, está claro que la versión parcheada de CCommandBuffer::Initialize tiene muchos bloques añadidos, lo que la hace parecer bastante diferente a la versión sin parchear.

Después de aplicar ingeniería inversa estática a esa función, hay dos llamadas a CD2DSharedBuffer::GetBufferSize.
La primera llamada obtiene el tamaño para asignar en el new y la segunda llamada obtiene el mismo tamaño para el memcpy.

Todo parece correcto inicialmente. Sin embargo, antes de la asignación, realiza algunas operaciones con el tamaño.

Obtiene buffer_size y buffer_size2 llamando a la misma función CD2DSharedBuffer::GetBufferSize, devolviendo ambas el mismo valor. Pero en el new realiza una preoperación, una división entera de buffer_size por 0x90 y luego multiplicando por 0x90, mientras que en el memcpy usa el buffer_size2 devuelto sin operar sobre él.
Con estas operaciones, descubrí que el tamaño finalmente usado en el new y en el memcpy puede ser diferente.
buffer_size = buffer_size2 (tamaños devueltos)
size_new= buffer_size/0x90 x 0x90
size_memcpy=buffer_size2
Por ejemplo, si buffer_size es 0x91
buffer_size = buffer_size2=0x91
size_new= buffer_size/0x90 x 0x90 =0x90
size_memcpy= buffer_size2= 0x91
Este ejemplo demuestra que hay un desbordamiento de montón. Se están copiando más bytes de los asignados, y el tamaño es controlable.
Por ejemplo, si buffer_size es 0x23f como se usó en el POC.
buffer_size = buffer_size2=0x23F
size_new= buffer_size/0x90 x 0x90 =0x1b0
size_memcpy== buffer_size2=0x23f
Con la función vulnerable analizada, quería ver cómo llegar a la función vulnerable CCommandBuffer::Initialize. Aquí es donde las cosas comienzan a complicarse.
Observando las referencias a esta función, parece que se llega a ella desde métodos de la clase CPrimitiveGroup:

Dichos métodos se pueden acceder desde la vftable de objetos CPrimitiveGroup:
Tiene su constructor: