mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['', 'src/binary-exploitation/ios-exploiting/ios-physical-uaf
This commit is contained in:
parent
ebb7a1b19e
commit
b3abdaa2b7
@ -1,99 +1,99 @@
|
||||
# iOS Physical Use-After-Free via IOSurface
|
||||
# iOS Physische use-after-free via IOSurface
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
## Physical use-after-free
|
||||
## Physischer use-after-free
|
||||
|
||||
This is a summary from the post from [https://alfiecg.uk/2024/09/24/Kernel-exploit.html](https://alfiecg.uk/2024/09/24/Kernel-exploit.html) moreover further information about exploit using this technique can be found in [https://github.com/felix-pb/kfd](https://github.com/felix-pb/kfd)
|
||||
Dies ist eine Zusammenfassung des Beitrags von [https://alfiecg.uk/2024/09/24/Kernel-exploit.html](https://alfiecg.uk/2024/09/24/Kernel-exploit.html). Weitere Informationen zu Exploits, die diese Technik verwenden, finden sich in [https://github.com/felix-pb/kfd](https://github.com/felix-pb/kfd)
|
||||
|
||||
### Memory management in XNU <a href="#memory-management-in-xnu" id="memory-management-in-xnu"></a>
|
||||
### Speicherverwaltung in XNU <a href="#memory-management-in-xnu" id="memory-management-in-xnu"></a>
|
||||
|
||||
Der **virtuelle Adressraum** für User-Prozesse auf iOS reicht von **0x0 bis 0x8000000000**. Diese Adressen zeigen jedoch nicht direkt auf den physischen Speicher. Stattdessen übersetzt der **kernel** virtuelle Adressen über **page tables** in tatsächliche **physische Adressen**.
|
||||
Der **virtuelle Adressraum** für Benutzerprozesse unter iOS reicht von **0x0 bis 0x8000000000**. Diese Adressen werden jedoch nicht direkt auf physischen Speicher abgebildet. Stattdessen verwendet der **Kernel** **Seitentabellen**, um virtuelle Adressen in tatsächliche **physische Adressen** zu übersetzen.
|
||||
|
||||
#### Levels of Page Tables in iOS
|
||||
#### Ebenen der Seitentabellen in iOS
|
||||
|
||||
Page tables sind hierarchisch in drei Ebenen organisiert:
|
||||
Seitentabellen sind hierarchisch in drei Ebenen organisiert:
|
||||
|
||||
1. **L1 Page Table (Level 1)**:
|
||||
* Jeder Eintrag repräsentiert einen großen Bereich des virtuellen Speichers.
|
||||
* Deckt **0x1000000000 bytes** (oder **256 GB**) virtuellen Speicher ab.
|
||||
* Jeder Eintrag repräsentiert hier einen großen Bereich des virtuellen Speichers.
|
||||
* Er deckt **0x1000000000 Bytes** (oder **256 GB**) virtuellen Speicher ab.
|
||||
2. **L2 Page Table (Level 2)**:
|
||||
* Ein Eintrag repräsentiert einen kleineren Bereich von **0x2000000 bytes** (32 MB).
|
||||
* Ein L1-Eintrag kann auf eine L2-Tabelle zeigen, wenn er den gesamten Bereich nicht direkt mappt.
|
||||
* Ein Eintrag repräsentiert hier einen kleineren Bereich des virtuellen Speichers, nämlich **0x2000000 Bytes** (32 MB).
|
||||
* Ein L1-Eintrag kann auf eine L2-Tabelle zeigen, wenn er den gesamten Bereich nicht selbst abbilden kann.
|
||||
3. **L3 Page Table (Level 3)**:
|
||||
* Die feinste Ebene, bei der jeder Eintrag eine einzelne **4 KB**-Speicherseite abbildet.
|
||||
* Ein L2-Eintrag kann auf eine L3-Tabelle zeigen, wenn detailliertere Kontrolle nötig ist.
|
||||
* Dies ist die feinste Ebene, in der jeder Eintrag eine einzelne **4 KB** Speicherseite abbildet.
|
||||
* Ein L2-Eintrag kann auf eine L3-Tabelle zeigen, wenn eine feinere Auflösung erforderlich ist.
|
||||
|
||||
#### Mapping Virtual to Physical Memory
|
||||
#### Abbildung von virtuellem zu physischem Speicher
|
||||
|
||||
* **Direct Mapping (Block Mapping)**:
|
||||
* Manche Einträge in einer page table mappen direkt einen Bereich virtueller Adressen auf einen zusammenhängenden Bereich physischer Adressen (wie eine Abkürzung).
|
||||
* **Pointer to Child Page Table**:
|
||||
* Wenn feinere Kontrolle benötigt wird, kann ein Eintrag auf einer Ebene (z. B. L1) auf eine **child page table** der nächsten Ebene (z. B. L2) zeigen.
|
||||
* **Direkte Abbildung (Block Mapping)**:
|
||||
* Einige Einträge in einer Seitentabelle **bilden direkt einen Bereich virtueller Adressen** auf einen zusammenhängenden Bereich physischer Adressen ab (wie eine Abkürzung).
|
||||
* **Zeiger auf untergeordnete Seitentabelle**:
|
||||
* Wenn eine feinere Steuerung notwendig ist, kann ein Eintrag einer Ebene (z. B. L1) auf eine **untergeordnete Seitentabelle** der nächsten Ebene (z. B. L2) zeigen.
|
||||
|
||||
#### Example: Mapping a Virtual Address
|
||||
#### Beispiel: Abbildung einer virtuellen Adresse
|
||||
|
||||
Angenommen, du versuchst auf die virtuelle Adresse **0x1000000000** zuzugreifen:
|
||||
Angenommen, Sie greifen auf die virtuelle Adresse **0x1000000000** zu:
|
||||
|
||||
1. **L1 Table**:
|
||||
* Der kernel überprüft den L1-Page-Table-Eintrag, der dieser virtuellen Adresse entspricht. Zeigt er auf eine **L2 page table**, geht er zu dieser L2-Tabelle.
|
||||
* Der Kernel prüft den L1-Seitentabelleneintrag, der dieser virtuellen Adresse entspricht. Wenn dieser einen **Zeiger auf eine L2-Seitentabelle** enthält, geht er zu dieser L2-Tabelle.
|
||||
2. **L2 Table**:
|
||||
* Der kernel prüft die L2-Page-Table für eine detailliertere Zuordnung. Zeigt dieser Eintrag auf eine **L3 page table**, geht es weiter dorthin.
|
||||
* Der Kernel prüft die L2-Seitentabelle für eine detailliertere Abbildung. Wenn dieser Eintrag auf eine **L3-Seitentabelle** zeigt, geht er dorthin.
|
||||
3. **L3 Table**:
|
||||
* Der kernel liest den finalen L3-Eintrag aus, der auf die **physische Adresse** der tatsächlichen Speicherseite zeigt.
|
||||
* Der Kernel sucht den finalen L3-Eintrag, der auf die **physische Adresse** der tatsächlichen Speicherseite zeigt.
|
||||
|
||||
#### Example of Address Mapping
|
||||
#### Beispiel einer Adressabbildung
|
||||
|
||||
Wenn du die physische Adresse **0x800004000** in den ersten Index der L2-Tabelle schreibst, dann:
|
||||
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.
|
||||
* Das ist ein **Block Mapping** auf L2-Ebene.
|
||||
* Das ist eine **Block-Abbildung** auf L2-Ebene.
|
||||
|
||||
Alternativ, wenn der L2-Eintrag auf eine L3-Tabelle zeigt:
|
||||
|
||||
* Jede 4 KB-Seite im virtuellen Adressbereich **0x1000000000 -> 0x1002000000** würde durch einzelne Einträge in der L3-Tabelle gemappt werden.
|
||||
* Jede 4 KB-Seite im virtuellen Adressbereich **0x1000000000 -> 0x1002000000** würde durch einzelne Einträge in der L3-Tabelle abgebildet werden.
|
||||
|
||||
### Physical use-after-free
|
||||
### Physischer use-after-free
|
||||
|
||||
Ein **physical use-after-free** (UAF) tritt auf, wenn:
|
||||
Ein **physischer use-after-free** (UAF) tritt auf, wenn:
|
||||
|
||||
1. Ein Prozess Speicher als **readable and writable** allokiert.
|
||||
2. Die **page tables** aktualisiert werden, sodass dieser Speicher auf eine bestimmte physische Adresse gemappt wird, auf die der Prozess zugreifen kann.
|
||||
3. Der Prozess den Speicher **dealloziert** (freigibt).
|
||||
4. Aufgrund eines **Bugs** vergisst der kernel jedoch, die Zuordnung aus den page tables zu entfernen, obwohl der entsprechende physische Speicher als frei markiert wird.
|
||||
5. Der kernel kann diesen "freigegebenen" physischen Speicher dann für andere Zwecke neu allozieren, z. B. für **kernel data**.
|
||||
6. Da die Zuordnung nicht entfernt wurde, kann der Prozess weiterhin auf diesen physischen Speicher **lesen und schreiben**.
|
||||
1. Ein Prozess etwas Speicher als **lesbar und beschreibbar** alloziert.
|
||||
2. Die **Seitentabellen** werden aktualisiert, um diesen Speicher auf eine bestimmte physische Adresse abzubilden, auf die der Prozess zugreifen kann.
|
||||
3. Der Prozess **deallokiert** (freigibt) den Speicher.
|
||||
4. Aufgrund eines **Fehlers** vergisst der Kernel jedoch, die Abbildung aus den Seitentabellen zu entfernen, obwohl er den entsprechenden physischen Speicher als frei markiert.
|
||||
5. Der Kernel kann diesen "freigegebenen" physischen Speicher dann für andere Zwecke neu verwenden, z. B. für **Kernel-Daten**.
|
||||
6. Da die Abbildung nicht entfernt wurde, kann der Prozess weiterhin **auf diesen physischen Speicher lesen und schreiben**.
|
||||
|
||||
Das bedeutet, der Prozess kann auf **Seiten von kernel-Speicher** zugreifen, die sensible Daten oder Strukturen enthalten können, was einem Angreifer ermöglichen könnte, **kernel memory** zu manipulieren.
|
||||
Das bedeutet, dass der Prozess auf **Seiten des Kernel-Speichers** zugreifen kann, die sensible Daten oder Strukturen enthalten könnten, und einem Angreifer möglicherweise erlauben, **Kernel-Speicher zu manipulieren**.
|
||||
|
||||
### IOSurface Heap Spray
|
||||
|
||||
Da der Angreifer nicht kontrollieren kann, welche spezifischen kernel-Seiten einer freigegebenen Seite zugewiesen werden, verwendet er die Technik **heap spray**:
|
||||
Da der Angreifer nicht kontrollieren kann, welche spezifischen Kernel-Seiten für den freigegebenen Speicher verwendet werden, nutzt er eine Technik namens **Heap Spray**:
|
||||
|
||||
1. Der Angreifer **erstellt eine große Anzahl von IOSurface-Objekten** im kernel-Speicher.
|
||||
2. Jedes IOSurface-Objekt enthält einen **magic value** in einem seiner Felder, der das Identifizieren erleichtert.
|
||||
3. Sie **scannen die freigegebenen Seiten**, um zu sehen, ob eines dieser IOSurface-Objekte auf einer freigegebenen Seite gelandet ist.
|
||||
4. Wenn sie ein IOSurface-Objekt auf einer freigegebenen Seite finden, können sie es verwenden, um **kernel memory** zu lesen und zu schreiben.
|
||||
1. Der Angreifer **erstellt eine große Anzahl von IOSurface-Objekten** im Kernel-Speicher.
|
||||
2. Jedes IOSurface-Objekt enthält einen **magischen Wert** in einem seiner Felder, wodurch es leicht zu identifizieren ist.
|
||||
3. Sie **scannen die freigegebenen Seiten**, um zu sehen, ob sich eines dieser IOSurface-Objekte auf einer freigegebenen Seite niedergelassen hat.
|
||||
4. Wenn sie ein IOSurface-Objekt auf einer freigegebenen Seite finden, können sie es nutzen, um **Kernel-Speicher zu lesen und zu schreiben**.
|
||||
|
||||
Mehr Infos dazu in [https://github.com/felix-pb/kfd/tree/main/writeups](https://github.com/felix-pb/kfd/tree/main/writeups)
|
||||
|
||||
> [!TIP]
|
||||
> Beachte, dass iOS 16+ (A12+) Geräte Hardware-Mitigationen (wie PPL oder SPTM) bringen, die physical UAF-Techniken deutlich weniger praktikabel machen.
|
||||
> PPL erzwingt strikte MMU-Schutzmechanismen auf Seiten, die mit Code-Signing, Entitlements und sensiblen kernel-Daten zusammenhängen. Selbst wenn eine Seite wiederverwendet wird, werden Writes aus userland oder kompromittiertem kernel-Code auf PPL-geschützte Seiten blockiert.
|
||||
> Secure Page Table Monitor (SPTM) erweitert PPL, indem es page table-Updates selbst härter absichert. Es stellt sicher, dass selbst privilegierter kernel-Code nicht stillschweigend freed pages remappen oder Mappings ohne sichere Checks manipulieren kann.
|
||||
> KTRR (Kernel Text Read-Only Region) sperrt den Kernel-Code-Bereich nach dem Boot als read-only. Das verhindert Laufzeit-Modifikationen am Kernel-Code und schließt einen großen Angriffsvektor, auf den physical UAF-Exploits oft angewiesen sind.
|
||||
> Außerdem sind IOSurface-Allocations weniger vorhersehbar und schwerer in benutzerzugängliche Regionen zu mappen, wodurch der „Magic-Value-Scanning“-Trick deutlich unzuverlässiger wird. Und IOSurface ist jetzt durch Entitlements und Sandbox-Restriktionen geschützt.
|
||||
> Beachte, dass iOS 16+ (A12+) Geräte Hardware-Mitigationen (wie PPL oder SPTM) mitbringen, die physische UAF-Techniken deutlich weniger praktikabel machen.
|
||||
> PPL erzwingt strikte MMU-Schutzmaßnahmen für Seiten, die mit code signing, entitlements und sensiblen Kernel-Daten zusammenhängen. Somit werden Schreibzugriffe aus userland oder von kompromittiertem Kernel-Code auf PPL-geschützte Seiten blockiert.
|
||||
> Secure Page Table Monitor (SPTM) erweitert PPL, indem es die Seitentabellenupdates selbst härtert. Es stellt sicher, dass selbst privilegierter Kernel-Code nicht stillschweigend freigegebene Seiten remappen oder Abbildungen manipulieren kann, ohne sichere Prüfungen zu durchlaufen.
|
||||
> KTRR (Kernel Text Read-Only Region) sperrt den Code-Bereich des Kernels nach dem Boot als read-only. Das verhindert Laufzeitänderungen am Kernel-Code und schließt damit einen großen Angriffsvektor, auf den physische UAF-Exploits oft angewiesen sind.
|
||||
> Außerdem sind `IOSurface`-Allokationen weniger vorhersehbar und schwieriger in benutzerzugängliche Regionen zu mappen, was den „magischer Wert“-Scan wesentlich unzuverlässiger macht. Und `IOSurface` ist jetzt durch entitlements und sandbox-Beschränkungen geschützt.
|
||||
|
||||
### Step-by-Step Heap Spray Process
|
||||
### Schritt-für-Schritt Heap Spray-Prozess
|
||||
|
||||
1. **Spray IOSurface Objects**: Der Angreifer erzeugt viele IOSurface-Objekte mit einem speziellen Identifier ("magic value").
|
||||
2. **Scan Freed Pages**: Sie prüfen, ob eines der Objekte auf einer freigegebenen Seite zugewiesen wurde.
|
||||
3. **Read/Write Kernel Memory**: Durch Manipulation von Feldern im IOSurface-Objekt erlangen sie die Fähigkeit zu **arbitrary reads and writes** im kernel-Speicher. Das erlaubt ihnen:
|
||||
* Ein Feld zu verwenden, um **jeden 32-bit Wert** im kernel-Speicher zu lesen.
|
||||
* Ein anderes Feld zu verwenden, um **64-bit Werte zu schreiben**, wodurch eine stabile **kernel read/write primitive** entsteht.
|
||||
1. **Spray IOSurface Objects**: Der Angreifer erstellt viele IOSurface-Objekte mit einem speziellen Bezeichner ("magischer Wert").
|
||||
2. **Scan Freed Pages**: Sie prüfen, ob eines der Objekte auf einer freigegebenen Seite alloziert wurde.
|
||||
3. **Read/Write Kernel Memory**: Durch Manipulation von Feldern im IOSurface-Objekt erlangen sie die Fähigkeit zu **beliebigen Reads und Writes** im Kernel-Speicher. Das erlaubt ihnen:
|
||||
* Ein Feld zu verwenden, um **jeden 32-Bit-Wert** im Kernel-Speicher zu lesen.
|
||||
* Ein anderes Feld zu verwenden, um **64-Bit-Werte zu schreiben**, wodurch ein stabiler **Kernel read/write primitive** entsteht.
|
||||
|
||||
Generate IOSurface objects with the magic value IOSURFACE\_MAGIC to later search for:
|
||||
Erzeuge IOSurface-Objekte mit dem magischen Wert IOSURFACE\_MAGIC, um später danach zu suchen:
|
||||
```c
|
||||
void spray_iosurface(io_connect_t client, int nSurfaces, io_connect_t **clients, int *nClients) {
|
||||
if (*nClients >= 0x4000) return;
|
||||
@ -148,25 +148,25 @@ free(surfaceIDs);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
### Erreichen von Kernel-Lese-/Schreibzugriff mit IOSurface
|
||||
### Kernel-Lese-/Schreibzugriff mit IOSurface erreichen
|
||||
|
||||
Nachdem Kontrolle über ein IOSurface-Objekt im Kernel-Speicher erreicht wurde (auf eine freigegebene physische Seite abgebildet, die aus dem userspace zugänglich ist), können wir es für **beliebige Kernel-Lese- und Schreiboperationen** verwenden.
|
||||
Nachdem Kontrolle über ein IOSurface-Objekt im Kernel-Speicher erreicht wurde (auf eine freigegebene physische Seite abgebildet, die vom userspace zugänglich ist), können wir es für **beliebige Kernel-Lese- und Schreiboperationen** verwenden.
|
||||
|
||||
**Wichtige Felder in IOSurface**
|
||||
|
||||
Das IOSurface-Objekt hat zwei entscheidende Felder:
|
||||
Die IOSurface hat zwei entscheidende Felder:
|
||||
|
||||
1. **Use Count Pointer**: Ermöglicht ein **32-Bit read**.
|
||||
2. **Indexed Timestamp Pointer**: Ermöglicht ein **64-Bit write**.
|
||||
1. **Use Count Pointer**: Ermöglicht ein **32-bit read**.
|
||||
2. **Indexed Timestamp Pointer**: Ermöglicht ein **64-bit write**.
|
||||
|
||||
Indem wir diese Zeiger überschreiben, leiten wir sie auf beliebige Adressen im Kernel-Speicher um und ermöglichen Lese-/Schreibzugriff.
|
||||
Durch Überschreiben dieser Pointer leiten wir sie auf beliebige Adressen im Kernel-Speicher um und ermöglichen so Lese-/Schreibzugriff.
|
||||
|
||||
#### 32-Bit Kernel-Lesezugriff
|
||||
|
||||
Um einen Lesevorgang durchzuführen:
|
||||
Um einen Lesezugriff durchzuführen:
|
||||
|
||||
1. Überschreibe den **use count pointer**, sodass er auf die Zieladresse minus einem 0x14-Byte-Offset zeigt.
|
||||
2. Verwende die Methode `get_use_count`, um den Wert an dieser Adresse zu lesen.
|
||||
1. Überschreibe den **use count pointer**, sodass er auf die Zieladresse minus einem 0x14-Byte-Offset zeigt.
|
||||
2. Benutze die Methode `get_use_count`, um den Wert an dieser Adresse zu lesen.
|
||||
```c
|
||||
uint32_t get_use_count(io_connect_t client, uint32_t surfaceID) {
|
||||
uint64_t args[1] = {surfaceID};
|
||||
@ -184,12 +184,12 @@ iosurface_set_use_count_pointer(info.object, orig);
|
||||
return value;
|
||||
}
|
||||
```
|
||||
#### 64-Bit Kernel-Schreiben
|
||||
#### 64-Bit Kernel Write
|
||||
|
||||
Um einen Schreibvorgang auszuführen:
|
||||
Um einen Schreibvorgang durchzuführen:
|
||||
|
||||
1. Überschreibe den **indexierten Zeitstempelzeiger** mit der Zieladresse.
|
||||
2. Verwende die `set_indexed_timestamp`-Methode, um einen 64-Bit-Wert zu schreiben.
|
||||
1. Überschreibe den **indexed timestamp pointer** auf die Zieladresse.
|
||||
2. Verwende die Methode `set_indexed_timestamp`, um einen 64-Bit-Wert zu schreiben.
|
||||
```c
|
||||
void set_indexed_timestamp(io_connect_t client, uint32_t surfaceID, uint64_t value) {
|
||||
uint64_t args[3] = {surfaceID, 0, value};
|
||||
@ -206,10 +206,10 @@ iosurface_set_indexed_timestamp_pointer(info.object, orig);
|
||||
#### Zusammenfassung des Exploit-Ablaufs
|
||||
|
||||
1. **Trigger Physical Use-After-Free**: Freie Seiten stehen zur Wiederverwendung zur Verfügung.
|
||||
2. **Spray IOSurface Objects**: Viele IOSurface-Objekte mit einem eindeutigen "magic value" im kernel memory allozieren.
|
||||
3. **Identify Accessible IOSurface**: Eine IOSurface auf einer freigegebenen Seite finden, die Sie kontrollieren.
|
||||
4. **Abuse Use-After-Free**: Pointer im IOSurface-Objekt manipulieren, um über IOSurface methods beliebiges **kernel read/write** zu ermöglichen.
|
||||
2. **Spray IOSurface Objects**: Allokiere viele IOSurface-Objekte mit einem eindeutigen "magic value" im Kernel-Speicher.
|
||||
3. **Identify Accessible IOSurface**: Finde ein IOSurface auf einer freigegebenen Seite, die du kontrollierst.
|
||||
4. **Abuse Use-After-Free**: Ändere Pointer im IOSurface-Objekt, um über IOSurface-Methoden beliebige **kernel read/write** zu ermöglichen.
|
||||
|
||||
Mit diesen Primitiven stellt der Exploit kontrollierte **32-bit reads** und **64-bit writes** auf kernel memory bereit. Weitere Jailbreak-Schritte könnten stabilere read/write-Primitiven erfordern, die zusätzliche Schutzmechanismen umgehen müssen (z. B. PPL auf neueren arm64e-Geräten).
|
||||
Mit diesen Primitiven ermöglicht der Exploit kontrollierte **32-bit reads** und **64-bit writes** auf den Kernel-Speicher. Weitere jailbreak-Schritte könnten stabilere read/write primitives erfordern, die das Umgehen zusätzlicher Schutzmechanismen nötig machen (z. B. PPL auf neueren arm64e-Geräten).
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user