
Proof-of-Concept für lokale Privilege Escalation für CVE-2023-20938, eine Use-after-Free in Android Binder, die Root erreicht und SELinux auf anfälligen Test-Builds deaktiviert.
Ein Proof-of-Concept zur lokalen Privilegieneskalation für CVE-2023-20938, eine Use-After-Free-Schwachstelle im Android-Binder-Treiber. Von einer unprivilegierten Shell erlangt es uid 0 und setzt SELinux auf permissive, dann startet es eine Root-Shell.
Ziel für diesen Build: Android Cuttlefish / Goldfish AVD, x86_64, Kernel 5.10.107.
⚠️ Nur für autorisierte Forschung / Bildungszwecke. Führen Sie dies nur gegen Ihre eigenen Testgeräte und Emulatoren aus. Der Fehler ist im aktuellen Android behoben; dieser PoC zielt auf einen alten, absichtlich verwundbaren Test-Build. Keine Garantie.

Aufgenommen mit asciinema und als GIF gerendert mit agg:
drivers/android/binder.c, binder_transaction_buffer_release()binder_transaction_buffer_release() vertraut einer vom Angreifer bereitgestellten offsets_size. Das Senden einer Transaktion, deren offsets_size ein Byte kürzer als ein vollständiger Eintrag ist (sizeof(offset) - 1 == 7), führt dazu, dass der Freigabepfad das abschließende flat_binder_object falsch parst und den Referenzzähler eines binder_node übermäßig dekrementiert, wodurch dieser freigegeben wird, während noch eine veraltete Referenz existiert.
Der Exploit verknüpft einen Cross-Cache-Leak mit einem beliebigen Lesezugriff und einem kontrollierten Schreibzugriff und überschreibt dann Berechtigungen. Schritt für Schritt (siehe main() in poc_cf.c):
B. Cross-cache leak
free a wave of binder_nodes (kmalloc-128) -> page returns to the buddy
allocator -> reclaim the page with eventpoll epitems (eventpoll_epi cache,
0x80-byte objects). A dangling binder transaction now reads kernel
pointers out of an epitem, leaking a struct file and its epitem address.
C. Arbitrary read
re-trigger the UAF and use a sprayed fake binder_node to turn binder's
hlist_del unlink into a controlled *(where) = what write. Two writes
redirect a victim file's f_inode at a fake inode overlaid on the epitem
and mark it S_PRIVATE. FIGETBSZ on the file then returns
*(epitem.event.data + 24): a steerable 4-byte read.
D/E/F. Privilege escalation
defeat KASLR (leak eventfd_fops via f_op), walk init_task's task list to
the launcher's cred, zero its uid/gid set and seccomp.mode, then zero
selinux_state to drop SELinux to permissive.
G. A pre-forked, eventfd-free launcher execs a root shell.
Zwei unprivilegierte Prozesse müssen einen Binder-Knoten teilen, um die UAF zu treiben; über den ITokenManager des hwservicemanagers (createToken /get-by-token).
clang -static -Wall -Wextra -o poc_cf poc_cf.c -lpthread
binder.h muss neben poc_cf.c liegen. Der Build ist absichtlich statisch, damit das einzelne Binärprogramm auf dem Ziel ohne vorhandene Toolchain läuft.
Führen Sie aus Ihrem Cuttlefish-Host-Paketverzeichnis den AVD mit dem passenden Kernel + Initramfs aus:
HOME=$PWD ./bin/launch_cvd \
--kernel_path=bzImage \
--initramfs_path=initramfs.img
adb push poc_cf /data/local/tmp/
adb shell /data/local/tmp/poc_cf
Ein erfolgreicher Durchlauf durchläuft die Schritte und endet in einer Root-Shell:
Der Exploit ist probabilistisch. Jede Stufe wiederholt intern.
Egal, ob Sie einen sauberen Abbruch oder eine Gast-Panik sehen, führen Sie ihn einfach erneut aus (das /data des AVD wird beim Neustart gelöscht, also übertragen Sie das Binärprogramm nach einer Panik erneut).
Wenn die Wiedergewinnungsrate auf einem langsameren oder ausgelasteten Ziel schlecht ist, verlängern Sie die Wartezeiten oder erhöhen Sie die Spray-Anzahl (die #defines nahe dem Anfang von poc_cf.c):
| Makro | Standard | Bedeutung |
|---|---|---|
SETTLE_US | 5000 | Pause nach der Freigabe des Knotens, vor dem Sprayen |
FAKE_SPRAY_COUNT | 8 | blockierte sendmsg()s, die um die Wiedergewinnung des Slots konkurrieren |
FAKE_WAIT_US | 10000 | Pause nach dem Freigeben der Sprays, vor dem Unlink |
PRESKIP_US | 1000 | Pause nach dem opfernden ersten sendmsg |
KW_RETRY_COUNT | 8 | Versuche pro einzelnen Unlink-Schreibzugriff |
STAGE_C_TRIES | 8 | Versuche, den beliebigen Lesezugriff online zu bringen |
Die Strukturoffsets und die nicht randomisierte Symbol-Baseline (*_NOKASLR) sind spezifisch für diesen exakten 5.10.107-Build und werden anderswo nicht funktionieren. Um auf einen anderen Kernel zu portieren, aktualisieren Sie den Offset-Block und den Symbol-Block nahe dem Anfang von poc_cf.c mit Werten aus dem passenden vmlinux. Ich habe es auf dem Pixel 7 nach dem Extrahieren der Offsets ausprobiert.
– Googles Android Offensive Security Blog [https://androidoffsec.withgoogle.com/posts/attacking-android-binder-analysis-and-exploitation-of-cve-2023-20938/]