
Exploit de prueba de concepto para CVE-2022-37969, una escalada de privilegios local en el controlador Windows Common Log File System. Demuestra heap spray, robo de tokens y escritura arbitraria en el kernel para obtener privilegios de SYSTEM.
autores: Ricardo Narvaja & Daniel Kazimirow (Solid)
Solo con fines de demostración. El exploit completo funciona en sistemas vulnerables Windows 11 21H2.
PoC funcional basado en información previamente publicada por Zscaler
Consulte el artículo Understanding the CVE-2022-37969 Windows Common Log File System Driver Local Privilege Escalation.
Recorrido de explotación:
El escenario utilizado aquí fue Windows 11 21H2 (OS Build 22000.918) clfs.sys v10.0.22000.918
El primer paso es crear un archivo llamado MyLog.blf en la carpeta pública (%public%), utilizando la función CreateLogFile():



Luego crea varios archivos de registro con nombres aleatorios usando un bucle.
Y dentro del bucle, llama a nuestra función getBigPoolInfo():

Llama a NtQuerySystemInformation(), con 0x42 (66 decimal) como primer argumento, devolverá en v5 la información sobre las asignaciones realizadas en el bigpool, cuya estructura es de tipo SYSTEM_BIGPOOL_INFORMATION.

Tenemos que llamar a esta función dos veces. La primera devolverá un error, pero nos dará el tamaño correcto del búfer para llamar la segunda vez y obtener la información deseada.

v5 recibirá la información de la estructura SYSTEM_BIG_POOL_INFORMATION.

El número de asignaciones en el bigpool se almacena en el primer campo llamado Count; en el segundo campo hay un arreglo de estructuras SYSTEM_BIGPOOL_ENTRY.

Luego buscaremos en todas las estructuras la etiqueta "Clfs" y el tamaño 0x7a00.

Almacena en un arreglo llamado kernelAddrArray la VirtualAddress que es el primer campo de cada estructura que tiene etiqueta CLFS y tamaño 0x7a00. De ahora en adelante, los pools que cumplan ambas condiciones se llamarán: "pools correctos".

Además de almacenar cada pool correcto en el arreglo, almacena el último pool correcto encontrado en el contenido de la variable a2, que se utiliza como argumento de la función.

De esta manera, a2 siempre apunta al último pool correcto con etiqueta CLFS y tamaño 0x7a00 creado.
La variable v26 siempre almacena el pool correcto anterior encontrado, ya que es igual a v24 (v26=v24), antes de llamar a getBigPoolinfo(), pero v24 se actualiza al salir de esta llamada con el último pool correcto encontrado, y v26 se queda con el pool correcto anterior encontrado.

Luego resta ambas direcciones, y en caso de que el resultado sea negativo, invierte los operandos para que siempre sea positivo.

De esta manera, en v32 se almacenará la diferencia entre la VirtualAddress de los dos últimos pools correctos encontrados.
Luego hace algo similar, en este caso v23 es inicialmente cero, así que hace v23=v32 la primera vez.

La siguiente vez en el bucle v23 todavía tiene el mismo valor y no es cero, por lo que se rompe y va aquí.

V32 tiene la última diferencia y v23 la anterior; si son iguales, sale e incrementa uno, pero reinicia el contador a cero.
La idea es encontrar 6 comparaciones consecutivas de etiquetas CLFS y tamaño 0x7a00 cuyas diferencias sean iguales, y esa diferencia será 0x11000. Veremos al ejecutar que cuando encuentre 6 (ya que empieza desde cero) consecutivas con distancias iguales, dará ese valor de diferencia entre ellas.


Allí vemos que encontró 6 consecutivas y salió del bucle de creación de archivos de registro.
En la carpeta "public" podemos ver los archivos creados.

Nuestra función craftFile() abre el archivo original (MyLog.blf) y lo modifica para desencadenar el error.