iOS Exploiting
Physikalisches Use-After-Free
Dies ist eine Zusammenfassung des Beitrags von https://alfiecg.uk/2024/09/24/Kernel-exploit.html. Weitere Informationen über Exploits, die diese Technik verwenden, finden Sie unter https://github.com/felix-pb/kfd.
Speicherverwaltung in XNU
Der virtuelle Adressraum für Benutzerprozesse auf iOS reicht von 0x0 bis 0x8000000000. Diese Adressen sind jedoch nicht direkt auf physischen Speicher abgebildet. Stattdessen verwendet der Kernel Seitentabellen, um virtuelle Adressen in tatsächliche physische Adressen zu übersetzen.
Ebenen der Seitentabellen in iOS
Seitentabellen sind hierarchisch in drei Ebenen organisiert:
L1 Seitentabelle (Ebene 1):
Jeder Eintrag hier repräsentiert einen großen Bereich virtuellen Speichers.
Sie deckt 0x1000000000 Bytes (oder 256 GB) virtuellen Speicher ab.
L2 Seitentabelle (Ebene 2):
Ein Eintrag hier repräsentiert einen kleineren Bereich virtuellen Speichers, speziell 0x2000000 Bytes (32 MB).
Ein L1-Eintrag kann auf eine L2-Tabelle verweisen, wenn er den gesamten Bereich nicht selbst abbilden kann.
L3 Seitentabelle (Ebene 3):
Dies ist die feinste Ebene, bei der jeder Eintrag eine einzelne 4 KB Speicherseite abbildet.
Ein L2-Eintrag kann auf eine L3-Tabelle verweisen, wenn eine genauere Kontrolle erforderlich ist.
Abbildung von virtuellem zu physischem Speicher
Direkte Abbildung (Blockabbildung):
Einige Einträge in einer Seitentabelle bilden einen Bereich virtueller Adressen auf einen zusammenhängenden Bereich physischer Adressen ab (wie eine Abkürzung).
Zeiger auf die Kind-Seitentabelle:
Wenn eine genauere Kontrolle erforderlich ist, kann ein Eintrag in einer Ebene (z. B. L1) auf eine Kind-Seitentabelle in der nächsten Ebene (z. B. L2) verweisen.
Beispiel: Abbildung einer virtuellen Adresse
Angenommen, Sie versuchen, auf die virtuelle Adresse 0x1000000000 zuzugreifen:
L1-Tabelle:
Der Kernel überprüft den L1-Seitentabelleneintrag, der dieser virtuellen Adresse entspricht. Wenn er einen Zeiger auf eine L2-Seitentabelle hat, geht er zu dieser L2-Tabelle.
L2-Tabelle:
Der Kernel überprüft die L2-Seitentabelle auf eine detailliertere Abbildung. Wenn dieser Eintrag auf eine L3-Seitentabelle verweist, fährt er dort fort.
L3-Tabelle:
Der Kernel sucht den endgültigen L3-Eintrag, der auf die physische Adresse der tatsächlichen Speicherseite verweist.
Beispiel für die Adressabbildung
Wenn Sie die physische Adresse 0x800004000 in den ersten Index der L2-Tabelle schreiben, dann:
Virtuelle Adressen von 0x1000000000 bis 0x1002000000 werden auf physische Adressen von 0x800004000 bis 0x802004000 abgebildet.
Dies ist eine Blockabbildung auf der L2-Ebene.
Alternativ, wenn der L2-Eintrag auf eine L3-Tabelle verweist:
Jede 4 KB-Seite im virtuellen Adressbereich 0x1000000000 -> 0x1002000000 würde durch einzelne Einträge in der L3-Tabelle abgebildet.
Physikalisches Use-After-Free
Ein physikalisches Use-After-Free (UAF) tritt auf, wenn:
Ein Prozess Speicher als lesbar und schreibbar allokiert.
Die Seitentabellen werden aktualisiert, um diesen Speicher auf eine bestimmte physische Adresse abzubilden, auf die der Prozess zugreifen kann.
Der Prozess den Speicher deallokiert (freigibt).
Aufgrund eines Bugs vergisst der Kernel, die Abbildung aus den Seitentabellen zu entfernen, obwohl er den entsprechenden physischen Speicher als frei markiert.
Der Kernel kann dann diesen "freigegebenen" physischen Speicher für andere Zwecke, wie Kernel-Daten, reallokieren.
Da die Abbildung nicht entfernt wurde, kann der Prozess weiterhin lesen und schreiben in diesen physischen Speicher.
Das bedeutet, dass der Prozess auf Seiten des Kernel-Speichers zugreifen kann, die sensible Daten oder Strukturen enthalten könnten, was einem Angreifer potenziell ermöglicht, den Kernel-Speicher zu manipulieren.
Exploitation-Strategie: Heap Spray
Da der Angreifer nicht kontrollieren kann, welche spezifischen Kernel-Seiten auf den freigegebenen Speicher zugewiesen werden, verwenden sie eine Technik namens Heap Spray:
Der Angreifer erstellt eine große Anzahl von IOSurface-Objekten im Kernel-Speicher.
Jedes IOSurface-Objekt enthält einen magischen Wert in einem seiner Felder, was die Identifizierung erleichtert.
Sie scannen die freigegebenen Seiten, um zu sehen, ob eines dieser IOSurface-Objekte auf einer freigegebenen Seite gelandet ist.
Wenn sie ein IOSurface-Objekt auf einer freigegebenen Seite finden, können sie es verwenden, um Kernel-Speicher zu lesen und zu schreiben.
Weitere Informationen dazu finden Sie unter https://github.com/felix-pb/kfd/tree/main/writeups.
Schritt-für-Schritt Heap Spray-Prozess
Spray IOSurface-Objekte: Der Angreifer erstellt viele IOSurface-Objekte mit einem speziellen Identifikator ("magischer Wert").
Scannen freigegebener Seiten: Sie überprüfen, ob eines der Objekte auf einer freigegebenen Seite zugewiesen wurde.
Lesen/Schreiben von Kernel-Speicher: Durch Manipulation der Felder im IOSurface-Objekt erhalten sie die Möglichkeit, willkürliche Lese- und Schreibvorgänge im Kernel-Speicher durchzuführen. Dies ermöglicht ihnen:
Ein Feld zu verwenden, um einen beliebigen 32-Bit-Wert im Kernel-Speicher zu lesen.
Ein anderes Feld zu verwenden, um 64-Bit-Werte zu schreiben, wodurch eine stabile Kernel-Lese-/Schreibprimitive erreicht wird.
Generieren Sie IOSurface-Objekte mit dem magischen Wert IOSURFACE_MAGIC, um später danach zu suchen:
Suche nach IOSurface
-Objekten in einer freigegebenen physischen Seite:
Erreichen von Kernel Read/Write mit IOSurface
Nachdem wir die Kontrolle über ein IOSurface-Objekt im Kernel-Speicher (zu einer freigegebenen physischen Seite, die aus dem Benutzerspeicher zugänglich ist, gemappt) erlangt haben, können wir es für willkürliche Kernel-Lese- und Schreiboperationen verwenden.
Wichtige Felder in IOSurface
Das IOSurface-Objekt hat zwei entscheidende Felder:
Use Count Pointer: Ermöglicht ein 32-Bit-Lesen.
Indexed Timestamp Pointer: Ermöglicht ein 64-Bit-Schreiben.
Durch das Überschreiben dieser Zeiger leiten wir sie an willkürliche Adressen im Kernel-Speicher um, was Lese-/Schreibfähigkeiten ermöglicht.
32-Bit Kernel-Lesen
Um ein Lesen durchzuführen:
Überschreiben Sie den Use Count Pointer, um auf die Zieladresse minus eines 0x14-Byte-Offsets zu zeigen.
Verwenden Sie die Methode
get_use_count
, um den Wert an dieser Adresse zu lesen.
64-Bit Kernel Write
Um einen Schreibvorgang durchzuführen:
Überschreiben Sie den indizierten Zeitstempelzeiger mit der Zieladresse.
Verwenden Sie die Methode
set_indexed_timestamp
, um einen 64-Bit-Wert zu schreiben.
Exploit Flow Recap
Trigger Physical Use-After-Free: Freie Seiten stehen zur Wiederverwendung zur Verfügung.
Spray IOSurface Objects: Viele IOSurface-Objekte mit einem einzigartigen "magischen Wert" im Kernel-Speicher allokieren.
Identify Accessible IOSurface: Ein IOSurface auf einer freigegebenen Seite finden, die Sie kontrollieren.
Abuse Use-After-Free: Zeiger im IOSurface-Objekt modifizieren, um beliebiges Kernel-Lesen/Schreiben über IOSurface-Methoden zu ermöglichen.
Mit diesen Primitiven bietet der Exploit kontrollierte 32-Bit-Lesevorgänge und 64-Bit-Schreibvorgänge im Kernel-Speicher. Weitere Jailbreak-Schritte könnten stabilere Lese-/Schreibprimitive beinhalten, die möglicherweise das Umgehen zusätzlicher Schutzmaßnahmen erfordern (z. B. PPL auf neueren arm64e-Geräten).
Last updated