iOS Exploiting
Tip
Učite i vežbajte AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.
iOS Exploit Mitigations
1. Code Signing / Runtime Signature Verification
Introduced early (iPhone OS → iOS) Ovo je jedna od osnovnih zaštita: sav izvršni kod (apps, dynamic libraries, JIT-ed code, extensions, frameworks, caches) mora biti kriptografski potpisan od strane lanca sertifikata čiji je koren Apple-ovo poverenje. U runtime-u, pre nego što se binarni fajl učita u memoriju (ili pre izvođenja skokova preko određenih granica), sistem proverava njegov potpis. Ako je kod modifikovan (flipovani bitovi, patchovan) ili nepotpisan, učitavanje ne uspeva.
- Sprečava: fazu „classic payload drop + execute“ u exploit lancima; arbitrarno ubacivanje koda; modifikovanje postojećeg binarnog fajla da se ubaci zlonamerna logika.
- Detalji mehanizma:
- Mach-O loader (i dynamic linker) proveravaju code pages, segmente, entitlements, team ID-eve, i da li potpis pokriva sadržaj fajla.
- Za memorijske regione kao što su JIT cache-ovi ili dinamički generisan kod, Apple zahteva da stranice budu potpisane ili validirane putem specijalnih API-ja (npr.
mprotectsa code-sign proverama). - Potpis uključuje entitlements i identifikatore; OS zahteva da određeni API-ji ili privilegovane sposobnosti zahtevaju specifična entitlements koja se ne mogu falsifikovati.
Example
Zamisli da exploit dobije code execution u procesu i pokuša da upiše shellcode u heap i skoči na njega. Na iOS-u, ta stranica bi morala biti označena kao executable **i** zadovoljiti code-signature ograničenja. Pošto shellcode nije potpisan Apple-ovim sertifikatom, skok ne uspeva ili sistem odbacuje promenu te memorijske oblasti u executable.2. CoreTrust
Introduced around iOS 14+ era (or gradually in newer devices / later iOS) CoreTrust je subsistem koji vrši runtime signature validation binarnih fajlova (uključujući system i user binare) protiv Apple-ovog root sertifikata umesto oslanjanja na keširane userland trust store-ove.
- Sprečava: post-install tampering binarnih fajlova, jailbreaking tehnike koje pokušavaju da zamene ili patchuju system libraries ili user apps; varanje sistema zamenom trusted binarnih fajlova zlonamernim verzijama.
- Detalji mehanizma:
- Umesto da veruje lokalnoj trust bazi ili kešu sertifikata, CoreTrust dohvaća ili se odnosi direktno na Apple-ov root ili verifikuje intermediate sertifikate u sigurnom lancu.
- Osigurava da se izmene (npr. u filesystem-u) postojećih binarnih fajlova otkriju i odbace.
- Povezuje entitlements, team ID-eve, code signing flag-ove i drugu metadata sa binarnim fajlom u vreme učitavanja.
Example
Jailbreak bi mogao pokušati da zameni `SpringBoard` ili `libsystem` patchovanom verzijom da bi stekao persistenciju. Ali kada loader OS-a ili CoreTrust proveri, primeti mismatch potpisa (ili modifikovane entitlements) i odbije da izvrši.3. Data Execution Prevention (DEP / NX / W^X)
Introduced in many OSes earlier; iOS had NX-bit / w^x for a long time DEP nameće da stranice označene kao writable (za podatke) budu non-executable, i stranice označene kao executable budu non-writable. Ne možete jednostavno upisati shellcode u heap ili stack i izvršiti ga.
- Sprečava: direktno izvršavanje shellcode-a; klasičan buffer-overflow → skok na injektovani shellcode.
- Detalji mehanizma:
- MMU / memory protection flag-ovi (putem page table-a) nameću razdvajanje.
- Bilo koji pokušaj da se writable stranica označi kao executable pokreće sistemsku proveru (i ili je zabranjen ili zahteva code-sign odobrenje).
- U mnogim slučajevima, pravljenje stranica executable zahteva korišćenje OS API-ja koji nameću dodatna ograničenja ili provere.
Example
Overflow upisuje shellcode na heap. Napadač pokušava `mprotect(heap_addr, size, PROT_EXEC)` da bi je učinio executable. Ali sistem odbija ili validira da nova stranica mora proći code-sign ograničenja (što shellcode ne može).4. Address Space Layout Randomization (ASLR)
Introduced in iOS ~4–5 era (roughly iOS 4–5 timeframe) ASLR nasumično pomera baze adresa ključnih memorijskih regiona: libraries, heap, stack, itd., pri svakom pokretanju procesa. Adrese gadgeta se menjaju između pokretanja.
- Sprečava: hardkodiranje adresa gadgeta za ROP/JOP; statične exploit lance; slepe skokove na poznate offset-e.
- Detalji mehanizma:
- Svaka učitana biblioteka / dinamički modul se rebaze-uje na nasumičan offset.
- Stack i heap base pointer-i se randomizuju (u okviru određenih entropijskih ograničenja).
- Ponekad i drugi regioni (npr. mmap alokacije) su takođe randomizovani.
- U kombinaciji sa mitigacijama za information-leak, primorava napadača da prvo leak-uje adresu ili pointer da otkrije base adrese u runtime-u.
Example
ROP lanč očekuje gadget na `0x….lib + offset`. Ali pošto je `lib` relociran drugačije pri svakom pokretanju, hardkodirani lanac ne uspeva. Exploit mora prvo da leak-uje base adresu modula pre nego što izračuna adrese gadgeta.5. Kernel Address Space Layout Randomization (KASLR)
Introduced in iOS ~ (iOS 5 / iOS 6 timeframe) Analogno korisničkom ASLR-u, KASLR nasumično pomera bazu kernel text-a i drugih kernel struktura pri podizanju sistema.
- Sprečava: kernel-level exploit-e koji se oslanjaju na fiksne lokacije kernel koda ili podataka; statične kernel exploit-e.
- Detalji mehanizma:
- Pri svakom boot-u, kernel base adresa se randomizuje (u okviru opsega).
- Kernel data strukture (kao
task_structs,vm_map, itd.) mogu biti takođe relocirane ili offsetovane. - Napadači moraju prvo da leak-uju kernel pointer-e ili koriste information disclosure ranjivosti da izračunaju offset-e pre nego što hijack-uju kernel strukture ili kod.
Example
Lokalna ranjivost cilja da korumpira kernel function pointer (npr. u `vtable`) na `KERN_BASE + offset`. Ali pošto je `KERN_BASE` nepoznat, napadač mora prvo da ga leak-uje (npr. putem read primitive) pre nego što izračuna pravu adresu za korupciju.6. Kernel Patch Protection (KPP / AMCC)
Introduced in newer iOS / A-series hardware (post around iOS 15–16 era or newer chips) KPP (aka AMCC) kontinuirano prati integritet kernel text stranica (putem hash-a ili checksuma). Ako detektuje tampering (patch-e, inline hook-ove, modifikacije koda) van dozvoljenih prozora, pokreće kernel panic ili reboot.
- Sprečava: persistent kernel patching (modifikovanje kernel instrukcija), inline hook-ove, statičke overwrite-ove funkcija.
- Detalji mehanizma:
- Hardver ili firmware modul prati kernel text region.
- Periodično ili na zahtev re-hash-uje stranice i upoređuje sa očekivanim vrednostima.
- Ako dođe do neslaganja van benignih update prozora, izaziva panic uređaja (da bi se izbegla persistent zlonamernost).
- Napadači moraju izbeći detekcione prozore ili koristiti legitimne puteve za patchovanje.
Example
Exploit pokušava da patch-uje kernel funkciju prolog (npr. `memcmp`) da bi presretao pozive. Ali KPP primeti da hash code stranice više ne odgovara očekivanoj vrednosti i pokreće kernel panic, srušivši uređaj pre nego što patch postane stabilan.7. Kernel Text Read‐Only Region (KTRR)
Introduced in modern SoCs (post ~A12 / newer hardware) KTRR je hardverski sprovođen mehanizam: jednom kada se kernel text zaključa rano tokom boota, postaje read-only iz EL1 (kernel) nivoa, sprečavajući dalja pisanja u code strane.
- Sprečava: bilo kakve modifikacije kernel koda nakon boota (npr. patchovanje, in-place code injection) na EL1 privilegovanom nivou.
- Detalji mehanizma:
- Tokom boota (u secure/bootloader fazi), memory controller (ili sigurna hardverska jedinica) označava fizičke stranice koje sadrže kernel text kao read-only.
- Čak i ako exploit dobije pune kernel privilegije, ne može pisati u te stranice da bi patch-ovao instrukcije.
- Da bi ih modifikovao, napadač mora prvo kompromitovati boot chain ili subvert-ovati sam KTRR.
Example
Privilege-escalation exploit skače u EL1 i pokušava da upiše trampoline u kernel funkciju (npr. u `syscall` handler). Ali zato što su stranice zaključane kao read-only od strane KTRR-a, upis ne uspeva (ili izaziva fault), pa patch-ovi nisu primenjeni.8. Pointer Authentication Codes (PAC)
Introduced with ARMv8.3 (hardware), Apple beginning with A12 / iOS ~12+
- PAC je hardverska funkcija uvedena u ARMv8.3-A da detektuje manipulisanje vrednostima pointer-a (return addresses, function pointers, određeni data pointer-i) ubacivanjem malog kriptografskog potpisa („MAC“) u neiskorišćene visoke bitove pointer-a.
- Potpis („PAC“) se računa preko vrednosti pointer-a plus modifier (kontekstualna vrednost, npr. stack pointer ili neki razlikujući podatak). Tako ista vrednost pointer-a u različitim kontekstima dobija različit PAC.
- U trenutku upotrebe, pre dereferenciranja ili grananja preko tog pointer-a, instrukcija za authenticate proverava PAC. Ako je validan, PAC se skida i dobija se čisti pointer; ako nije, pointer postaje „poisoned“ (ili se podiže fault).
- Ključevi koji se koriste za kreiranje/validaciju PAC-a žive u privilegovanim registrima (EL1, kernel) i nisu direktno dostupni iz user moda.
- Pošto nisu svi 64 bita pointer-a iskorišćeni u mnogim sistemima (npr. 48-bit address space), gornji bitovi su „slobodni“ i mogu držati PAC bez menjanja efektivne adrese.
Architectural Basis & Key Types
-
ARMv8.3 uvodi pet 128-bitnih ključeva (svaki implementiran putem dva 64-bit registra sistema) za pointer authentication.
-
APIAKey — za instruction pointers (domen “I”, ključ A)
-
APIBKey — drugi ključ za instruction pointers (domen “I”, ključ B)
-
APDAKey — za data pointer-e (domen “D”, ključ A)
-
APDBKey — za data pointer-e (domen “D”, ključ B)
-
APGAKey — „generic“ ključ, za potpisivanje ne-pointer podataka ili druge generičke upotrebe
-
Ovi ključevi se čuvaju u privilegovanim sistemskim registrima (dostupnim samo na EL1/EL2 itd.), nisu dostupni iz user moda.
-
PAC se računa putem kriptografskog funkcionala (ARM predlaže QARMA kao algoritam) koristeći:
- Vrednost pointer-a (kanonični deo)
- Modifier (kontekstualna vrednost, kao salt)
- Tajni ključ
- Neki interni tweak logiku Ako rezultujući PAC odgovara onome što je smešteno u gornjim bitovima pointer-a, autentikacija uspeva.
Instruction Families
Konvencija imenovanja je: PAC / AUT / XPAC, zatim sufiksi domena.
PACxxinstrukcije potpisuju pointer i ubacuju PACAUTxxinstrukcije authenticate + strip (validiraju i uklanjaju PAC)XPACxxinstrukcije strip bez validacije
Domains / suffixes:
| Mnemonic | Meaning / Domain | Key / Domain | Example Usage in Assembly |
|---|---|---|---|
| PACIA | Sign instruction pointer with APIAKey | “I, A” | PACIA X0, X1 — sign pointer in X0 using APIAKey with modifier X1 |
| PACIB | Sign instruction pointer with APIBKey | “I, B” | PACIB X2, X3 |
| PACDA | Sign data pointer with APDAKey | “D, A” | PACDA X4, X5 |
| PACDB | Sign data pointer with APDBKey | “D, B” | PACDB X6, X7 |
| PACG / PACGA | Generic (non-pointer) signing with APGAKey | “G” | PACGA X8, X9, X10 (sign X9 with modifier X10 into X8) |
| AUTIA | Authenticate APIA-signed instruction pointer & strip PAC | “I, A” | AUTIA X0, X1 — check PAC on X0 using modifier X1, then strip |
| AUTIB | Authenticate APIB domain | “I, B” | AUTIB X2, X3 |
| AUTDA | Authenticate APDA-signed data pointer | “D, A” | AUTDA X4, X5 |
| AUTDB | Authenticate APDB-signed data pointer | “D, B” | AUTDB X6, X7 |
| AUTGA | Authenticate generic / blob (APGA) | “G” | AUTGA X8, X9, X10 (validate generic) |
| XPACI | Strip PAC (instruction pointer, no validation) | “I” | XPACI X0 — remove PAC from X0 (instruction domain) |
| XPACD | Strip PAC (data pointer, no validation) | “D” | XPACD X4 — remove PAC from data pointer in X4 |
Postoje specijalizovane / alias forme:
PACIASPje skraćeno zaPACIA X30, SP(potpiši link register koristeći SP kao modifier)AUTIASPjeAUTIA X30, SP(authenticate link register sa SP)- Kombinovane forme poput
RETAA,RETAB(authenticate-and-return) iliBLRAA(authenticate & branch) postoje u ARM ekstenzijama / podršci kompajlera. - Takođe varijante sa nul-modifierom:
PACIZA/PACIZBgde je modifier implicitno nula, itd.
Modifiers
Glavni cilj modifier-a je da veže PAC za specifičan kontekst tako da ista adresa potpisana u različitim kontekstima daje različite PAC-ove. To sprečava jednostavno reuse pointer-a preko frame-ova ili objekata. To je kao dodavanje soli hashu.
Dakle:
- Modifier je kontekstualna vrednost (drugi registar) koja se meša u PAC izračunavanje. Tipični izbori: stack pointer (
SP), frame pointer, ili neki object ID. - Korišćenje SP kao modifier-a je uobičajeno za potpisivanje return adresa: PAC je vezan za specifični stack frame. Ako pokušate da ponovo upotrebite LR u drugom frame-u, modifier se menja, pa PAC validacija ne uspe.
- Ista vrednost pointer-a potpisana pod različitim modifier-ima daje različite PAC-ove.
- Modifier ne mora biti tajan, ali idealno nije pod kontrolom napadača.
- Za instrukcije koje potpisuju ili verifikuju pointer-e gde nema smislenog modifier-a, neke forme koriste nulu ili implicitnu konstantu.
Apple / iOS / XNU Customizations & Observations
- Apple-ova implementacija PAC uključuje per-boot diversifiers tako da se ključevi ili tweak-ovi menjaju pri svakom boot-u, sprečavajući reuse između boot-ova.
- Takođe uključuju cross-domain mitigacije tako da PAC potpisan u user modu ne može lako biti reupotrebljen u kernel modu, itd.
- Na Apple M1 / Apple Silicon, reverzni inženjering je pokazao da postoji devet tipova modifier-a i Apple-specifični sistemski registri za kontrolu ključeva.
- Apple koristi PAC u mnogim kernel podsistemima: potpisivanje return adresa, integritet pointer-a u kernel podacima, signed thread context-e, itd.
- Google Project Zero je pokazao kako bi, pod snažnim memory read/write primitive-om u kernelu, neko mogao falsifikovati kernel PAC-ove (za A ključeve) na A12-era uređajima, ali Apple je zakrpio mnoge od tih puteva.
- U Apple-ovom sistemu, neki ključevi su globalni za ceo kernel, dok user procesi mogu dobiti per-process randomness ključeva.
PAC Bypasses
- Kernel-mode PAC: theoretical vs real bypasses
- Pošto su kernel PAC ključevi i logika strogo kontrolisani (privilegovani registri, diversifiers, domain izolacija), falsifikovanje proizvoljnih potpisanih kernel pointer-a je veoma teško.
- Azad-ov 2020 „iOS Kernel PAC, One Year Later“ izveštaj navodi da je u iOS 12-13 pronašao nekoliko parcijalnih bypass-ova (signing gadgets, reuse of signed states, unprotected indirect branches) ali ne i potpuni generički bypass. bazad.github.io
- Apple-ove „Dark Magic“ prilagodbe dodatno su suzile površine za eksploatisanje (domain switching, per-key enabling bits). i.blackhat.com
- Poznat je kernel PAC bypass CVE-2023-32424 na Apple silicon (M1/M2) prijavljen od strane Zecao Cai et al. i.blackhat.com
- Ali ti bypass-i često zavise od vrlo specifičnih gadget-a ili implementacionih bagova; nisu opšteprihvaćeni generički putevi.
Dakle kernel PAC se smatra veoma robusnim, iako nije potpuno savršen.
- User-mode / runtime PAC bypass techniques
Ovi su češći i iskorišćavaju nedostatke u tome kako se PAC primenjuje ili koristi u dynamic linking / runtime framework-ovima. Ispod su klase, sa primerima.
2.1 Shared Cache / A key issues
-
dyld shared cache je veliki pre-linked blob system framework-a i biblioteka. Pošto se toliko široko deli, function pointer-i unutar shared cache-a su „pre-signed“ i koriste ih mnogi procesi. Napadači ciljkaju te već potpisane pointer-e kao „PAC oracles“.
-
Neke tehnike bypass-a pokušavaju da ekstrahuju ili ponovo iskoriste A-key potpisane pointer-e prisutne u shared cache-u i ponovo ih iskoriste u gadgetima.
-
Predavanje “No Clicks Required” opisuje izgradnju orakla preko shared cache-a da se iščita relativne adrese i kombinovanje toga sa signed pointer-ima za bypass PAC-a. saelo.github.io
-
Takođe, import-ovi function pointer-a iz shared libraries u userspace su ponekad bili nedovoljno zaštićeni PAC-om, dopuštajući napadaču da dobije function pointer-e bez menjanja njihovog potpisa. (Project Zero bug entry) bugs.chromium.org
2.2 dlsym(3) / dynamic symbol resolution
-
Jedan poznat bypass je pozivanje
dlsym()da se dobije već potpisan function pointer (potpisan sa A-key, diversifier zero) i zatim ga koristiti. Poštodlsymvraća legitimno potpisan pointer, njegovo korišćenje zaobilazi potrebu za falsifikovanjem PAC-a. -
Epsilon-ov blog detaljno opisuje kako neki bypass-i iskorištavaju ovo: pozivanje
dlsym("someSym")vraća potpisani pointer i može se koristiti za indirektne pozive. blog.epsilon-sec.com -
Synacktiv-ov tekst “iOS 18.4 — dlsym considered harmful” opisuje bag: neki simboli resolver-ovani preko
dlsymna iOS 18.4 vraćaju pointer-e koji su netačno potpisani (ili sa buggy diversifier-ima), omogućavajući nenameran PAC bypass. Synacktiv -
Logika u dyld za dlsym uključuje: kada je
result->isCode, oni potpisuju vraćeni pointer sa__builtin_ptrauth_sign_unauthenticated(..., key_asia, 0), tj. kontekst nula. blog.epsilon-sec.com
Dakle, dlsym je čest vektor u user-mode PAC bypass-ima.
2.3 Other DYLD / runtime relocations
-
DYLD loader i dinamička relocaciona logika su kompleksni i ponekad privremeno mapiraju stranice kao read/write da bi uradili relocations, pa ih potom ponovo postave na read-only. Napadači iskorištavaju te vremenske prozore. Synacktiv-ovo predavanje opisuje “Operation Triangulation”, timing-baziran bypass PAC-a putem dinamičkih relocacija. Synacktiv
-
DYLD stranice su sada zaštićene sa SPRR / VM_FLAGS_TPRO (neki protection flag-ovi za dyld). Ali ranije verzije su imale slabije zaštite. Synacktiv
-
U WebKit exploit lancima, DYLD loader je često meta za PAC bypass. Slajdovi pominju da su mnogi PAC bypass-i ciljali DYLD loader (putem relocacija, interposer hook-ova). Synacktiv
2.4 NSPredicate / NSExpression / ObjC / SLOP
-
U userland exploit lancima, Objective-C runtime metode kao
NSPredicate,NSExpressioniliNSInvocationse koriste da se smugluju kontrolni pozivi bez očiglednog falsifikovanja pointer-a. -
Na starijim iOS verzijama (pre PAC), exploit je koristio fake NSInvocation objekte da pozove proizvoljne selektore nad kontrolisanim memorijama. Sa PAC-om su potrebne izmene. Ali tehnika SLOP (SeLector Oriented Programming) je proširena i pod PAC-om. Project Zero
-
Originalna SLOP tehnika je dozvoljavala chaining ObjC poziva kreiranjem lažnih invokacija; bypass se oslanja na to da ISA ili selector pointer-i ponekad nisu u potpunosti PAC-zaštićeni. Project Zero
-
U okruženjima gde je pointer authentication primenjen parcijalno, metode / selector-i / target pointer-i možda nisu uvek zaštićeni PAC-om, što ostavlja prostor za bypass.
Example Flow
Example Signing & Authenticating
``` ; Example: function prologue / return address protection my_func: stp x29, x30, [sp, #-0x20]! ; push frame pointer + LR mov x29, sp PACIASP ; sign LR (x30) using SP as modifier ; … body … mov sp, x29 ldp x29, x30, [sp], #0x20 ; restore AUTIASP ; authenticate & strip PAC ret; Example: indirect function pointer stored in a struct ; suppose X1 contains a function pointer PACDA X1, X2 ; sign data pointer X1 with context X2 STR X1, [X0] ; store signed pointer
; later retrieval: LDR X1, [X0] AUTDA X1, X2 ; authenticate & strip BLR X1 ; branch to valid target
; Example: stripping for comparison (unsafe) LDR X1, [X0] XPACI X1 ; strip PAC (instruction domain) CMP X1, #some_label_address BEQ matched_label
</details>
<details>
<summary>Primer</summary>
A buffer overflow prepisuje adresu za povratak na stacku. Napadač upisuje ciljnu adresu gadgeta ali ne može izračunati ispravan PAC. Kada funkcija vraća kontrolu, CPU-ova instrukcija `AUTIA` baci grešku zbog neslaganja PAC-a. Lanac ne uspeva.
Project Zero-ova analiza na A12 (iPhone XS) je pokazala kako Apple-ov PAC funkcioniše i metode falsifikovanja PAC-ova ako napadač ima primitiv čitanja/pisanja memorije.
</details>
### 9. **Branch Target Identification (BTI)**
**Uvedeno sa ARMv8.5 (kasniji hardver)**
BTI je hardverska funkcija koja proverava **indirektne ciljeve grana**: pri izvršavanju `blr` ili indirektnih poziva/skokova, cilj mora početi sa **BTI landing pad** (`BTI j` ili `BTI c`). Skakanje u adrese gadgeta koje nemaju landing pad izaziva izuzetak.
LLVM-ova implementacija opisuje tri varijante BTI instrukcija i kako se one mapiraju na tipove grana.
| BTI Variant | What it permits (which branch types) | Typical placement / use case |
|-------------|----------------------------------------|-------------------------------|
| **BTI C** | Targets of *call*-style indirect branches (e.g. `BLR`, or `BR` using X16/X17) | Put at entry of functions that may be called indirectly |
| **BTI J** | Targets of *jump*-style branches (e.g. `BR` used for tail calls) | Placed at the beginning of blocks reachable by jump tables or tail-calls |
| **BTI JC** | Acts as both C and J | Can be targeted by either call or jump branches |
- U kodu kompajliranom sa enforced branch target proverom, kompajleri ubacuju BTI instrukciju (C, J, ili JC) na svaki validan indirektno-granajući cilj (početci funkcija ili blokovi dostupni skokovima) tako da indirektne grane uspevaju samo do tih mesta.
- **Direktne grane / pozivi** (tj. fiks-adresni `B`, `BL`) **nisu ograničeni** od strane BTI. Pretpostavka je da su code page-ovi poverljivi i da napadač ne može da ih izmeni (tako da su direktne grane bezbedne).
- Takođe, **RET / return** instrukcije generalno nisu ograničene BTI jer su adrese za povratak zaštićene preko PAC ili mehanizama potpisivanja povratka.
#### Mehanizam i sprovođenje
- Kada CPU dekodira **indirektnu granu (BLR / BR)** u strani označenoj kao „guarded / BTI-enabled,“ proverava da li prva instrukcija na ciljnoj adresi predstavlja validan BTI (C, J, ili JC kako je dozvoljeno). Ako ne, nastaje **Branch Target Exception**.
- BTI instrukcija je enkodirana tako da ponovo koristi opcode-ove ranije rezervisane za NOP-ove (u ranijim ARM verzijama). Tako BTI-enabled binari ostaju kompatibilni unazad: na hardveru bez BTI podrške te instrukcije deluju kao NOP.
- Kompajlerski pass-ovi koji dodaju BTI umeću ih samo gde su potrebni: funkcijama koje se mogu pozivati indirektno, ili osnovnim blokovima ciljanima skokovima.
- Neki patch-evi i LLVM kod pokazuju da BTI nije ubačen za *sve* osnovne blokove — već samo one koji su potencijalni ciljevi grana (npr. iz switch / jump tabela).
#### Sinergija BTI + PAC
PAC štiti vrednost pokazivača (izvor) — osigurava da lanac indirektnih poziva / povrataka nije izmenjen.
BTI osigurava da čak i validan pokazivač može ciljati samo adekvatno označene ulazne tačke.
U kombinaciji, napadaču su potrebni i validan pokazivač sa ispravnim PAC-om i cilj koji ima postavljen BTI. To povećava težinu konstrukcije exploit gadget-a.
#### Primer
<details>
<summary>Primer</summary>
Exploit pokušava da pivotira u gadget na `0xABCDEF` koji ne počinje sa `BTI c`. CPU, pri izvršavanju `blr x0`, proveri cilj i baci grešku zato što instrukcija nema validan landing pad. Dakle, mnogi gadgeti postaju neupotrebljivi osim ako nemaju BTI prefiks.
</details>
### 10. **Privileged Access Never (PAN) & Privileged Execute Never (PXN)**
**Uvedeno u novijim ARMv8 ekstenzijama / iOS podršci (za ojačano jezgro)**
#### PAN (Privileged Access Never)
- **PAN** je funkcija uvedena u **ARMv8.1-A** koja sprečava **privilegovani kod** (EL1 ili EL2) da **čita ili piše** memoriju označenu kao **user-accessible (EL0)**, osim ako PAN nije eksplicitno onemogućen.
- Ideja: čak i ako je kernel prevaren ili kompromitovan, ne može proizvoljno dereferencirati user-space pokazivače bez prethodnog *isključivanja* PAN, čime se smanjuju rizici od exploit-a tipa **`ret2usr`** ili zloupotrebe buffer-a pod kontrolom korisnika.
- Kada je PAN omogućen (PSTATE.PAN = 1), svaka privilegovana load/store instrukcija koja pristupa virtuelnoj adresi koja je „accessible at EL0“ izaziva **permission fault**.
- Kernel, kada legitimno mora da pristupi user-space memoriji (npr. kopiranje podataka ka/iz korisničkih buffera), mora **privremeno da onemogući PAN** (ili koristiti „unprivileged load/store“ instrukcije) da bi omogućio taj pristup.
- U Linuxu na ARM64, podrška za PAN uvedena je oko 2015: kernel patch-evi su dodali detekciju funkcije i zamenili `get_user` / `put_user` itd. varijantama koje brišu PAN oko pristupa korisničkoj memoriji.
**Ključna nijansa / ograničenje / bug**
- Kao što su Siguza i drugi primetili, bug u specifikaciji (ili dvosmislena ponašanja) u ARM dizajnu znači da stranice koje su samo za izvršavanje (execute-only user mappings) (`--x`) možda **neće izazvati PAN**. Drugim rečima, ako je user page označen kao izvršni ali bez prava čitanja, kernelov pokušaj čitanja može zaobići PAN jer arhitektura smatra da „accessible at EL0“ zahteva pravo čitanja, a ne samo izvršavanje. Ovo dovodi do PAN zaobilaženja u određenim konfiguracijama.
- Zbog toga, ako iOS / XNU dozvoljava execute-only user stranice (kao što neke JIT ili code-cache postavke rade), kernel bi mogao nenamerno čitati iz njih čak i sa uključenim PAN-om. Ovo je poznato suptilno eksploatabilno područje na nekim ARMv8+ sistemima.
#### PXN (Privileged eXecute Never)
- **PXN** je bit u page table-u (u page table entry-ima, leaf ili block entry-ima) koji označava da stranica **nije izvršna kada se izvršava u privilegovanom režimu** (tj. kada EL1 izvršava).
- PXN sprečava kernel (ili bilo koji privilegovani kod) da skoči ili izvrši instrukcije iz user-space stranica čak i ako je kontrola preusmerena. U suštini, zaustavlja preusmeravanje toka izvršavanja na user memoriju na nivou kernela.
- U kombinaciji sa PAN, ovo osigurava da:
1. Kernel ne može (po defaultu) da čita ili piše user-space podatke (PAN)
2. Kernel ne može da izvršava user-space kod (PXN)
- U ARMv8 formatu page table-a, leaf entry-i imaju `PXN` bit (i takođe `UXN` za unprivileged execute-never) u svojim atributnim bitovima.
Dakle, čak i ako kernel ima korumpiran pokazivač funkcije koji pokazuje na user memoriju i pokuša da skoči tamo, PXN bit bi izazvao fault.
#### Model dozvola memorije & kako se PAN i PXN mapiraju na page table bitove
Da biste razumeli kako PAN / PXN rade, treba videti kako ARM-ov translacioni i permission model funkcioniše (pojednostavljeno):
- Svaka page ili block entry ima atributna polja uključujući **AP[2:1]** za dozvole pristupa (read/write, privileged vs unprivileged) i **UXN / PXN** bitove za execute-never restrikcije.
- Kada je PSTATE.PAN = 1 (omogućeno), hardver primenjuje modifikovana semantika: privilegovani pristupi stranicama označenim kao „accessible by EL0“ (tj. user-accessible) su zabranjeni (fault).
- Zbog pomenutog buga, stranice koje su označene samo kao izvršne (bez prava čitanja) možda se ne računaju kao „accessible by EL0“ pod određenim implementacijama, te zaobilaze PAN.
- Kada je PXN bit stranice postavljen, čak i ako dolazi fetch instrukcije sa višeg privilegijnog nivoa, izvršavanje je zabranjeno.
#### Korišćenje PAN / PXN u ojačanom OS-u (npr. iOS / XNU)
U dizajnu ojačanog kernela (kao što Apple može koristiti):
- Kernel omogućava PAN po defaultu (tako da je privilegovani kod ograničen).
- U putevima koji legitimno trebaju da čitaju ili pišu korisničke buffere (npr. syscall buffer copy, I/O, read/write user pointer), kernel privremeno **onemogućava PAN** ili koristi specijalne instrukcije za prelaženje.
- Nakon završetka pristupa korisničkim podacima, mora ponovo da omogući PAN.
- PXN se sprovodi putem page table-a: user stranice imaju PXN = 1 (tako da kernel ne može da ih izvršava), kernel stranice nemaju PXN (tako da kernel kod može da se izvršava).
- Kernel mora osigurati da nijedan kodni put ne prouzrokuje izvršni tok u user memoriju (što bi zaobišlo PXN) — pa su exploit lanci koji se oslanjaju na „skok u user-kontrolisani shellcode“ blokirani.
Zbog pomenutog PAN zaobilaženja preko execute-only stranica, u realnom sistemu Apple može onemogućiti ili zabraniti execute-only user stranice, ili zakrpiti specifikacijski nedostatak.
#### Površine napada, zaobilaženja i mitigacije
- **PAN zaobilaženje preko execute-only stranica**: kao što je diskutovano, spec dozvoljava prazninu: user stranice sa execute-only (bez prava čitanja) možda neće biti prepoznate kao „accessible at EL0,“ pa PAN neće blokirati kernel čitanja iz takvih stranica pod određenim implementacijama. To daje napadaču neobičan put da unese podatke preko „execute-only“ sekcija.
- **Temporal window exploit**: ako kernel isključi PAN na vremenski period duži nego što je neophodno, trkačka situacija ili zlonameran put može iskoristiti to vreme za nepredviđeni pristup korisničkoj memoriji.
- **Zaboravljeno ponovno omogućavanje**: ako kodne putanje ne uspeju da ponovo omoguće PAN, naredne kernel operacije mogu pogrešno da pristupaju korisničkoj memoriji.
- **Pogrešna konfiguracija PXN**: ako page table ne postavlja PXN na user stranice ili pogrešno mapira user kodne stranice, kernel bi mogao biti prevaren da izvrši user-space kod.
- **Speculacija / side-channels**: analogno spekulativnim zaobilaženjima, mogu postojati mikroarhitekturni efekti koji uzrokuju tranzijentno kršenje PAN / PXN provera (iako su takvi napadi visoko zavisni od dizajna CPU-a).
- **Kompleksne interakcije**: kod naprednijih funkcionalnosti (npr. JIT, shared memory, just-in-time code regions), kernel može zahtevati finu kontrolu da dozvoli određene memorijske pristupe ili izvršavanje u user-mapped regionima; dizajniranje tih scenarija bezbedno pod PAN/PXN ograničenjima nije trivijalno.
#### Primer
<details>
<summary>Code Example</summary>
Here are illustrative pseudo-assembly sequences showing enabling/disabling PAN around user memory access, and how a fault might occur.
// Suppose kernel entry point, PAN is enabled (privileged code cannot access user memory by default)
; Kernel receives a syscall with user pointer in X0 ; wants to read an integer from user space mov X1, X0 ; X1 = user pointer
; disable PAN to allow privileged access to user memory MSR PSTATE.PAN, #0 ; clear PAN bit, disabling the restriction
ldr W2, [X1] ; now allowed load from user address
; re-enable PAN before doing other kernel logic MSR PSTATE.PAN, #1 ; set PAN
; … further kernel work …
; Later, suppose an exploit corrupts a pointer to a user-space code page and jumps there BR X3 ; branch to X3 (which points into user memory)
; Because the target page is marked PXN = 1 for privileged execution, ; the CPU throws an exception (fault) and rejects execution
If the kernel had **not** set PXN on that user page, then the branch might succeed — which would be insecure.
Ako kernel NIJE postavio PXN na tu user page, grana bi mogla uspeti — što bi bilo nesigurno.
If the kernel forgets to re-enable PAN after user memory access, it opens a window where further kernel logic might accidentally read/write arbitrary user memory.
Ako kernel zaboravi da ponovo omogući PAN posle pristupa user memory, otvara se period u kome dalji kernel kod može slučajno da čita/piše proizvoljnu user memory.
If the user pointer is into an execute-only page (user page with only execute permission, no read/write), under the PAN spec bug, `ldr W2, [X1]` might **not** fault even with PAN enabled, enabling a bypass exploit, depending on implementation.
Ako user pointer pokazuje na execute-only page (user page sa samo execute dozvolom, bez read/write), zbog PAN spec buga, `ldr W2, [X1]` možda NEće fault-ovati čak i sa PAN omogućenim, što može omogućiti bypass exploit, zavisno od implementacije.
</details>
<details>
<summary>Example</summary>
A kernel vulnerability tries to take a user-provided function pointer and call it in kernel context (i.e. `call user_buffer`). Under PAN/PXN, that operation is disallowed or faults.
Kernel vulnerability pokušava da uzme user-provided function pointer i pozove ga u kernel context (tj. `call user_buffer`). Under PAN/PXN, ta operacija je zabranjena ili će fault-ovati.
</details>
---
### 11. **Top Byte Ignore (TBI) / Pointer Tagging**
**Introduced in ARMv8.5 / newer (or optional extension)**
TBI means the top byte (most-significant byte) of a 64-bit pointer is ignored by address translation. This lets OS or hardware embed **tag bits** in the pointer’s top byte without affecting the actual address.
- TBI stands for **Top Byte Ignore** (sometimes called *Address Tagging*). It is a hardware feature (available in many ARMv8+ implementations) that **ignores the top 8 bits** (bits 63:56) of a 64-bit pointer when performing **address translation / load/store / instruction fetch**.
- In effect, the CPU treats a pointer `0xTTxxxx_xxxx_xxxx` (where `TT` = top byte) as `0x00xxxx_xxxx_xxxx` for the purposes of address translation, ignoring (masking off) the top byte. The top byte can be used by software to store **metadata / tag bits**.
- This gives software “free” in-band space to embed a byte of tag in each pointer without altering which memory location it refers to.
- The architecture ensures that loads, stores, and instruction fetch treat the pointer with its top byte masked (i.e. tag stripped off) before performing the actual memory access.
Thus TBI decouples the **logical pointer** (pointer + tag) from the **physical address** used for memory operations.
#### Why TBI: Use cases and motivation
- **Pointer tagging / metadata**: You can store extra metadata (e.g. object type, version, bounds, integrity tags) in that top byte. When you later use the pointer, the tag is ignored at hardware level, so you don’t need to strip manually for the memory access.
- **Memory tagging / MTE (Memory Tagging Extension)**: TBI is the base hardware mechanism that MTE builds on. In ARMv8.5, the **Memory Tagging Extension** uses bits 59:56 of the pointer as a **logical tag** and checks it against an **allocation tag** stored in memory.
- **Enhanced security & integrity**: By combining TBI with pointer authentication (PAC) or runtime checks, you can force not just the pointer value but also the tag to be correct. An attacker overwriting a pointer without the correct tag will produce a mismatched tag.
- **Compatibility**: Because TBI is optional and tag bits are ignored by hardware, existing untagged code continues to operate normally. The tag bits effectively become “don’t care” bits for legacy code.
#### Example
<details>
<summary>Example</summary>
A function pointer included a tag in its top byte (say `0xAA`). An exploit overwrites the pointer low bits but neglects the tag, so when the kernel verifies or sanitizes, the pointer fails or is rejected.
Funkcioni pointer je imao tag u svom top byte-u (npr. `0xAA`). Exploit prepiše niže bitove pointera ali zanemari tag, pa kada kernel verifikuje ili sanitizuje, pointer ne prođe ili biva odbijen.
</details>
---
### 12. **Page Protection Layer (PPL)**
**Introduced in late iOS / modern hardware (iOS ~17 / Apple silicon / high-end models)** (some reports show PPL circa macOS / Apple silicon, but Apple is bringing analogous protections to iOS)
- PPL is designed as an **intra-kernel protection boundary**: even if the kernel (EL1) is compromised and has read/write capabilities, **it should not be able to freely modify** certain **sensitive pages** (especially page tables, code-signing metadata, kernel code pages, entitlements, trust caches, etc.).
- It effectively creates a **“kernel within the kernel”** — a smaller trusted component (PPL) with **elevated privileges** that alone can modify protected pages. Other kernel code must call into PPL routines to effect changes.
- This reduces the attack surface for kernel exploits: even with full arbitrary R/W/execute in kernel mode, exploit code must also somehow get into the PPL domain (or bypass PPL) to modify critical structures.
- On newer Apple silicon (A15+ / M2+), Apple is transitioning to **SPTM (Secure Page Table Monitor)**, which in many cases replaces PPL for page-table protection on those platforms.
Here’s how PPL is believed to operate, based on public analysis:
#### Use of APRR / permission routing (APRR = Access Permission ReRouting)
- Apple hardware uses a mechanism called **APRR (Access Permission ReRouting)**, which allows page table entries (PTEs) to contain small indices, rather than full permission bits. Those indices are mapped via APRR registers to actual permissions. This allows dynamic remapping of permissions per domain.
- PPL leverages APRR to segregate privilege within kernel context: only the PPL domain is permitted to update the mapping between indices and effective permissions. That is, when non-PPL kernel code writes a PTE or tries to flip permission bits, the APRR logic disallows it (or enforces read-only mapping).
- PPL code itself runs in a restricted region (e.g. `__PPLTEXT`) which is normally non-executable or non-writable until entry gates temporarily allow it. The kernel calls PPL entry points (“PPL routines”) to perform sensitive operations.
#### Gate / Entry & Exit
- When the kernel needs to modify a protected page (e.g. change permissions of a kernel code page, or modify page tables), it calls into a **PPL wrapper** routine, which does validation and then transitions into the PPL domain. Outside that domain, the protected pages are effectively read-only or non-modifiable by the main kernel.
- During PPL entry, the APRR mappings are adjusted so that memory pages in the PPL region are set to **executable & writable** within PPL. Upon exit, they are returned to read-only / non-writable. This ensures that only well-audited PPL routines can write to protected pages.
- Outside PPL, attempts by kernel code to write to those protected pages will fault (permission denied) because the APRR mapping for that code domain doesn’t permit writing.
#### Protected page categories
The pages that PPL typically protects include:
- Page table structures (translation table entries, mapping metadata)
- Kernel code pages, especially those containing critical logic
- Code-sign metadata (trust caches, signature blobs)
- Entitlement tables, signature enforcement tables
- Other high-value kernel structures where a patch would allow bypassing signature checks or credentials manipulation
The idea is that even if the kernel memory is fully controlled, the attacker cannot simply patch or rewrite these pages, unless they also compromise PPL routines or bypass PPL.
#### Known Bypasses & Vulnerabilities
1. **Project Zero’s PPL bypass (stale TLB trick)**
- A public writeup by Project Zero describes a bypass involving **stale TLB entries**.
- The idea:
1. Allocate two physical pages A and B, mark them as PPL pages (so they are protected).
2. Map two virtual addresses P and Q whose L3 translation table pages come from A and B.
3. Spin a thread to continuously access Q, keeping its TLB entry alive.
4. Call `pmap_remove_options()` to remove mappings starting at P; due to a bug, the code mistakenly removes the TTEs for both P and Q, but only invalidates the TLB entry for P, leaving Q’s stale entry live.
5. Reuse B (page Q’s table) to map arbitrary memory (e.g. PPL-protected pages). Because the stale TLB entry still maps Q’s old mapping, that mapping remains valid for that context.
6. Through this, the attacker can put writable mapping of PPL-protected pages in place without going through PPL interface.
- This exploit required fine control of physical mapping and TLB behavior. It demonstrates that a security boundary relying on TLB / mapping correctness must be extremely careful about TLB invalidations and mapping consistency.
- Project Zero commented that bypasses like this are subtle and rare, but possible in complex systems. Still, they regard PPL as a solid mitigation.
2. **Other potential hazards & constraints**
- If a kernel exploit can directly enter PPL routines (via calling the PPL wrappers), it might bypass restrictions. Thus argument validation is critical.
- Bugs in the PPL code itself (e.g. arithmetic overflow, boundary checks) can allow out-of-bounds modifications inside PPL. Project Zero observed that such a bug in `pmap_remove_options_internal()` was exploited in their bypass.
- The PPL boundary is irrevocably tied to hardware enforcement (APRR, memory controller), so it's only as strong as the hardware implementation.
#### Example
<details>
<summary>Code Example</summary>
Here’s a simplified pseudocode / logic showing how a kernel might call into PPL to modify protected pages:
Evo pojednostavljenog pseudocode / logike koja pokazuje kako kernel može pozvati PPL da izmeni zaštićene stranice:
</details>
```c
// In kernel (outside PPL domain)
function kernel_modify_pptable(pt_addr, new_entry) {
// validate arguments, etc.
return ppl_call_modify(pt_addr, new_entry) // call PPL wrapper
}
// In PPL (trusted domain)
function ppl_call_modify(pt_addr, new_entry) {
// temporarily enable write access to protected pages (via APRR adjustments)
aprr_set_index_for_write(PPL_INDEX)
// perform the modification
*pt_addr = new_entry
// restore permissions (make pages read-only again)
aprr_restore_default()
return success
}
// If kernel code outside PPL does:
*pt_addr = new_entry // a direct write
// It will fault because APRR mapping for non-PPL domain disallows write to that page
Kernel može da obavlja mnoge uobičajene operacije, ali samo preko ppl_call_* rutina može da menja zaštićena mappings ili da patch-uje code.
Example
Kernel exploit pokušava da prepiše entitlement table, ili da onemogući code-sign enforcement modifikovanjem kernel signature bloba. Pošto je ta stranica PPL-protected, upis je blokiran osim ako se ne ide preko PPL interface-a. Dakle, čak i sa kernel code execution, ne možete zaobići code-sign ograničenja ili proizvoljno menjati credential podatke. Na iOS 17+ neki uređaji koriste SPTM da dodatno izoluju PPL-managed pages.PPL → SPTM / Replacements / Future
- On Apple’s modern SoCs (A15 or later, M2 or later), Apple supports SPTM (Secure Page Table Monitor), which replaces PPL for page table protections.
- Apple calls out in documentation: “Page Protection Layer (PPL) and Secure Page Table Monitor (SPTM) enforce execution of signed and trusted code … PPL manages the page table permission overrides … Secure Page Table Monitor replaces PPL on supported platforms.”
- Arhitektura SPTM verovatno pomera više sprovođenja politike u monitor sa višim privilegijama izvan kontrole kernela, dodatno smanjujući trust boundary.
MTE | EMTE | MIE
Evo opisa na višem nivou kako EMTE radi u okviru Apple-ovog MIE podešavanja:
- Dodela taga
- Kada se memorija alocira (npr. u kernelu ili user space preko secure allocators), tom bloku se dodeljuje secret tag.
- Pointer koji se vraća korisniku ili kernelu sadrži taj tag u svojim visokim bitovima (koristeći TBI / top byte ignore mehanizme).
- Provera taga pri pristupu
- Kad god se izvrši load ili store koristeći pointer, hardware proverava da li se tag u pointeru slaže sa tagom memorijskog bloka (allocation tag). Ako se ne poklapa, odmah se javlja fault (pošto je synchronous).
- Pošto je synchronous, nema “delayed detection” prozora.
- Retagging pri free / reuse
- Kada se memorija oslobodi, allocator menja tag bloka (tako da stariji pointeri sa starim tagovima više ne odgovaraju).
- Use-after-free pointer bi zbog toga imao stale tag i prijavio bi mismatch pri pristupu.
- Differencijacija tagova suseda za hvatanje overflows
- Susedne alokacije dobijaju različite tagove. Ako buffer overflow prelije u memoriju suseda, tag mismatch izaziva fault.
- Ovo je naročito efikasno u otkrivanju malih overflows koji prelaze granicu.
- Obezbeđivanje poverljivosti taga
- Apple mora da spreči da vrednosti taga budu leaked (jer, ako napadač sazna tag, mogao bi da formira pointere sa ispravnim tagovima).
- Uključuju zaštite (microarchitectural / speculative controls) da bi izbegli side-channel leakage of tag bits.
- Integracija kernela i user-space
- Apple koristi EMTE ne samo u user-space već i u kernelu / OS-critical komponentama (da bi zaštitio kernel od memory corruption).
- Hardware/OS osiguravaju da pravila taga važe čak i kada kernel izvršava u ime user space.
Example
``` Allocate A = 0x1000, assign tag T1 Allocate B = 0x2000, assign tag T2// pointer P points into A with tag T1 P = (T1 << 56) | 0x1000
// Valid store *(P + offset) = value // tag T1 matches allocation → allowed
// Overflow attempt: P’ = P + size_of_A (into B region) *(P’ + delta) = value → pointer includes tag T1 but memory block has tag T2 → mismatch → fault
// Free A, allocator retags it to T3 free(A)
// Use-after-free: *(P) = value → pointer still has old tag T1, memory region is now T3 → mismatch → fault
</details>
#### Ograničenja i izazovi
- **Intrablock overflows**: Ako overflow ostane unutar iste alokacije (ne pređe granicu) i tag ostane isti, tag mismatch to neće detektovati.
- **Tag width limitation**: Dostupno je samo nekoliko bita (npr. 4 bita, ili mali domen) za tag — ograničen prostor imena.
- **Side-channel leaks**: Ako se tag bitovi mogu be leaked (putem cache / speculative execution), napadač može saznati validne tagove i zaobići zaštitu. Apple-ovo sprovođenje tag confidentiality ima za cilj da ovo ublaži.
- **Performance overhead**: Provere taga pri svakom load/store dodaju trošak; Apple mora optimizovati hardver da bi smanjio overhead.
- **Compatibility & fallback**: Na starijem hardveru ili delovima koji ne podržavaju EMTE mora postojati fallback. Apple tvrdi da je MIE omogućen samo na uređajima sa podrškom.
- **Complex allocator logic**: Allocator mora upravljati tagovima, retaggingom, poravnavanjem granica i izbegavati mis-tag collisions. Bugovi u logici allocator-a mogu uvesti ranjivosti.
- **Mixed memory / hybrid areas**: Neki delovi memorije mogu ostati netagovani (legacy), što otežava interoperabilnost.
- **Speculative / transient attacks**: Kao i kod mnogih mikroarhitektonskih zaštita, speculative execution ili micro-op fusions mogu transientno zaobići provere ili otkriti vrednosti tag bitova.
- **Limited to supported regions**: Apple može primenjivati EMTE samo u selektivnim, visokorizičnim oblastima (kernel, security-critical subsystems), a ne univerzalno.
---
## Ključna poboljšanja / razlike u odnosu na standardni MTE
Evo poboljšanja i izmena na koje Apple posebno ukazuje:
| Feature | Original MTE | EMTE (Apple’s enhanced) / MIE |
|---|---|---|
| **Check mode** | Supports synchronous and asynchronous modes. In async, tag mismatches are reported later (delayed)| Apple insists on **synchronous mode** by default—tag mismatches are caught immediately, no delay/race windows allowed.|
| **Coverage of non-tagged memory** | Accesses to non-tagged memory (e.g. globals) may bypass checks in some implementations | EMTE zahteva da pristupi iz tagovane regije ka netagovanoj memoriji takođe validiraju poznavanje taga, otežavajući zaobilaženje mešanim alokacijama.|
| **Tag confidentiality / secrecy** | Tags might be observable or leaked via side channels | Apple dodaje **Tag Confidentiality Enforcement**, koja pokušava da spreči leak-ovanje vrednosti taga (putem spekulativnih side-kanala itd.).|
| **Allocator integration & retagging** | MTE leaves much of allocator logic to software | Apple's secure typed allocators (kalloc_type, xzone malloc, etc.) integrišu se sa EMTE: kada se memorija alocira ili oslobodi, tagovi se upravljaju na finom nivou.|
| **Always-on by default** | In many platforms, MTE is optional or off by default | Apple omogućava EMTE / MIE po defaultu na podržanom hardveru (npr. iPhone 17 / A19) za kernel i mnoge user procese.|
Zbog toga što Apple kontroliše i hardver i softverski stack, može strogo primenjivati EMTE, izbeći performansne zamke i zatvoriti side-channel rupe.
---
## Kako EMTE funkcioniše u praksi (Apple / MIE)
Evo višeg nivoa opisa kako EMTE radi u Apple-ovom MIE podešavanju:
1. **Tag assignment**
- Kada se memorija alocira (npr. u kernelu ili user space preko secure allocators), tom bloku se dodeljuje **tajni tag**.
- Pokazivač koji se vraća korisniku ili kernelu uključuje taj tag u svojim visokim bitovima (koristeći TBI / top byte ignore mechanisms).
2. **Tag checking on access**
- Kad god se izvrši load ili store koristeći pokazivač, hardver proverava da li se tag pokazivača poklapa sa tagom memorijskog bloka (allocation tag). Ako se ne poklapaju, nastaje fault odmah (pošto je synchronous).
- Pošto je u synchronous režimu, nema prozora za “delayed detection”.
3. **Retagging on free / reuse**
- Kad se memorija oslobodi, allocator menja tag bloka (tako da stariji pokazivači sa starim tagom više ne odgovaraju).
- Use-after-free pokazivač će zbog toga imati zastareo tag i neće proći proveru pri pristupu.
4. **Neighbor-tag differentiation to catch overflows**
- Susednim alokacijama dodeljuju se različiti tagovi. Ako buffer overflow prelije u memoriju suseda, tag mismatch izaziva fault.
- Ovo je naročito efikasno za otkrivanje malih overflow-a koji prelaze granicu.
5. **Tag confidentiality enforcement**
- Apple mora sprečiti leak-ovanje vrednosti tagova (jer ako napadač sazna tag, mogao bi konstruisati pokazivače sa ispravnim tagom).
- Uključene su zaštite (mikroarhitektonske / spekulativne kontrole) da bi se izbeglo leak-ovanje tag bitova.
6. **Kernel and user-space integration**
- Apple koristi EMTE ne samo u user-space već i u kernelu / OS-critcal komponentama (da zaštiti kernel od korupcije memorije).
- Hardver/OS osigurava da pravila taga važe i kada kernel izvršava kod u ime user space-a.
Pošto je EMTE ugrađen u MIE, Apple ga koristi u synchronous modu preko ključnih površina napada, a ne samo kao opciju ili debug mod.
---
## Exception handling in XNU
Kada se desi **exception** (npr., `EXC_BAD_ACCESS`, `EXC_BAD_INSTRUCTION`, `EXC_CRASH`, `EXC_ARM_PAC`, itd.), **Mach layer** XNU kernela je odgovoran da ga presretne pre nego što postane UNIX-stil **signal** (kao `SIGSEGV`, `SIGBUS`, `SIGILL`, ...).
Ovaj proces uključuje više slojeva propagacije i obrade izuzetaka pre nego što stigne do user space-a ili bude konvertovan u BSD signal.
### Tok izuzetaka (High-Level)
1. **CPU triggers a synchronous exception** (npr. invalid pointer dereference, PAC failure, illegal instruction, itd.).
2. **Low-level trap handler** radi (`trap.c`, `exception.c` u XNU izvoru).
3. Trap handler poziva **`exception_triage()`**, jezgro Mach obrade izuzetaka.
4. `exception_triage()` odlučuje kako da usmeri izuzetak:
- Prvo ka **thread's exception port**.
- Zatim ka **task's exception port**.
- Zatim ka **host's exception port** (često `launchd` ili `ReportCrash`).
Ako nijedan od ovih portova ne obradi izuzetak, kernel može:
- **Konvertovati ga u BSD signal** (za user-space procese).
- **Panicirati** (za izuzetke u kernel-u).
### Osnovna funkcija: `exception_triage()`
Funkcija `exception_triage()` usmerava Mach izuzetke uz lanac mogućih handler-a dok jedan od njih ne obradi izuzetak ili dok ne postane fatalan. Definisana je u `osfmk/kern/exception.c`.
```c
void exception_triage(exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t codeCnt);
Tipičan tok poziva:
exception_triage() └── exception_deliver() ├── exception_deliver_thread() ├── exception_deliver_task() └── exception_deliver_host()
Ako sve zakaže → obrađuje se pomoću bsd_exception() → prevodi se u signal kao što je SIGSEGV.
Exception Ports
Svaki Mach objekat (thread, task, host) može registrovati exception ports, na koje se šalju poruke o izuzecima.
Definisani su API-jem:
task_set_exception_ports()
thread_set_exception_ports()
host_set_exception_ports()
Each exception port has:
- A mask (which exceptions it wants to receive)
- A port name (Mach port to receive messages)
- A behavior (how the kernel sends the message)
- A flavor (which thread state to include)
Debuggeri i rukovanje izuzecima
A debugger (npr. LLDB) postavlja exception port na ciljnu task ili thread, obično koristeći task_set_exception_ports().
Kada se desi izuzetak:
- Mach poruka se šalje debugger procesu.
- Debugger može da odluči da obrađuje (resume, modifikuje registre, preskoči instrukciju) ili ne obrađuje izuzetak.
- Ako debugger ne obrađuje, izuzetak se propagira na sledeći nivo (task → host).
Tok EXC_BAD_ACCESS
-
Thread dereferencira nevažeći pokazivač → CPU podiže Data Abort.
-
Kernel trap handler poziva
exception_triage(EXC_BAD_ACCESS, ...). -
Poruka se šalje na:
-
Thread port → (debugger može presresti breakpoint).
-
Ako debugger ignoriše → Task port → (process-level handler).
-
Ako se i to ignoriše → Host port (obično ReportCrash).
- Ako niko ne obrađuje →
bsd_exception()prevodi uSIGSEGV.
PAC Exceptions
Kada Pointer Authentication (PAC) zakaže (nepoklapanje potpisa), diže se poseban Mach izuzetak:
EXC_ARM_PAC(tip)- Codes mogu sadržati detalje (npr. tip ključa, tip pokazivača).
Ako binar ima flag TFRO_PAC_EXC_FATAL, kernel tretira PAC neuspehe kao fatalne, zaobilazeći debugger intercept. Ovo je da se spreči da napadači koriste debuggere da zaobiđu PAC provere i omogućeno je za platform binaries.
Software Breakpoints
A software breakpoint (int3 on x86, brk on ARM64) se implementira izazivanjem namernog kvara.
Debugger to presreće preko exception porta:
- Menja instruction pointer ili memoriju.
- Vraća originalnu instrukciju.
- Nastavlja izvršavanje.
Isti mehanizam vam omogućava da “uhvatite” PAC izuzetak — osim ako nije postavljen TFRO_PAC_EXC_FATAL, u kom slučaju nikada ne dođe do debugger-a.
Konverzija u BSD signale
Ako nijedan handler ne prihvati izuzetak:
-
Kernel poziva
task_exception_notify() → bsd_exception(). -
Ovo mapira Mach izuzetke na signale:
| Mach Exception | Signal |
|---|---|
| EXC_BAD_ACCESS | SIGSEGV or SIGBUS |
| EXC_BAD_INSTRUCTION | SIGILL |
| EXC_ARITHMETIC | SIGFPE |
| EXC_SOFTWARE | SIGTRAP |
| EXC_BREAKPOINT | SIGTRAP |
| EXC_CRASH | SIGKILL |
| EXC_ARM_PAC | SIGILL (ako nije fatalan) |
Key Files in XNU Source
-
osfmk/kern/exception.c→ Jezgroexception_triage(),exception_deliver_*(). -
bsd/kern/kern_sig.c→ Logika isporuke signala. -
osfmk/arm64/trap.c→ Niskonivoi trap handler-i. -
osfmk/mach/exc.h→ Exception codes i strukture. -
osfmk/kern/task.c→ Task exception port setup.
Stari kernel heap (Pre-iOS 15 / Pre-A12 era)
Kernel je koristio zone allocator (kalloc) podeljen u zone fiksne veličine.
Svaka zona je čuvala alokacije samo jedne veličinske klase.
Iz screenshot-a:
| Zone Name | Element Size | Example Use |
|---|---|---|
default.kalloc.16 | 16 bytes | Vrlo male kernel strukture, pokazivači. |
default.kalloc.32 | 32 bytes | Male strukture, header-i objekata. |
default.kalloc.64 | 64 bytes | IPC poruke, sitni kernel buffer-i. |
default.kalloc.128 | 128 bytes | Srednji objekti poput delova OSObject. |
| … | … | … |
default.kalloc.1280 | 1280 bytes | Velike strukture, IOSurface/graphics metadata. |
Kako je funkcionisalo:
- Svaki zahtev za alokaciju se zaokruži gore na najbližu veličinu zone.
(Npr. zahtev za 50 bajtova ide u
kalloc.64zonu). - Memorija u svakoj zoni se držala u freelist-u — chunk-ovi oslobođeni od kernel-a su vraćani u tu zonu.
- Ako bi overflow-ovao 64-bajtni buffer, prepisao bi sledeći objekat u istoj zoni.
Zbog toga su heap spraying / feng shui bili toliko efikasni: mogao si predvideti susede objekata tako što bi prskao alokacije iste veličinske klase.
Freelist
Unutar svake kalloc zone, oslobođeni objekti nisu vraćani odmah sistemu — išli su u freelist, linked list dostupnih chunk-ova.
-
Kada bi se chunk oslobodio, kernel bi upisao pokazivač na početak tog chunka → adresu sledećeg slobodnog chunka u istoj zoni.
-
Zona je čuvala HEAD pokazivač na prvi slobodni chunk.
-
Alokacija je uvek koristila trenutni HEAD:
-
Pop HEAD (vrati tu memoriju pozivaocu).
-
Ažuriraj HEAD = HEAD->next (smešteno u header-u oslobođenog chunka).
-
Slobodno vraćanje je guralo chunk-ove nazad:
-
freed_chunk->next = HEAD -
HEAD = freed_chunk
Dakle, freelist je bio običan linked list građen unutar same oslobođene memorije.
Normal state:
Zone page (64-byte chunks for example):
[ A ] [ F ] [ F ] [ A ] [ F ] [ A ] [ F ]
Freelist view:
HEAD ──► [ F ] ──► [ F ] ──► [ F ] ──► [ F ] ──► NULL
(next ptrs stored at start of freed chunks)
Eksploatisanje freelist
Pošto prvih 8 bajtova free chunk = freelist pointer, napadač ga može korumpirati:
-
Heap overflow u susedni freed chunk → prepiše njegov “next” pointer.
-
Use-after-free upis u freed object → prepiše njegov “next” pointer.
Zatim, pri sledećoj alokaciji te veličine:
- Alokator izvadi korumpovani chunk.
- Prati “next” pointer koji je napadač obezbedio.
- Vraća pointer na proizvoljnu memoriju, omogućavajući fake object primitives ili targeted overwrite.
Vizuelni primer freelist poisoning:
Before corruption:
HEAD ──► [ F1 ] ──► [ F2 ] ──► [ F3 ] ──► NULL
After attacker overwrite of F1->next:
HEAD ──► [ F1 ]
(next) ──► 0xDEAD_BEEF_CAFE_BABE (attacker-chosen)
Next alloc of this zone → kernel hands out memory at attacker-controlled address.
Ovaj freelist dizajn je činio exploit-ovanje izuzetno efektivnim pre hardeninga: predvidivi susedi iz heap sprays, raw pointer freelist links, i nedostatak razdvajanja tipova omogućavali su napadačima da eskaliraju UAF/overflow ranjivosti u arbitrarno upravljanje kernel memorijom.
Heap Grooming / Feng Shui
Cilj heap grooming-a je da oblikuje heap layout tako da, kada napadač izazove overflow ili use-after-free, ciljni (victim) objekat sedi odmah pored objekta pod kontrolom napadača.
Na taj način, kada dođe do korupcije memorije, napadač može pouzdano prepisati victim objekat kontrolisanim podacima.
Koraci:
- Spray allocations (fill the holes)
- Vremenom kernel heap postane fragmentisan: neke zone imaju praznine gde su stari objekti bili freed.
- Napadač prvo izvrši veliki broj dummy allocations da popuni te praznine, tako da heap postane „packed” i predvidljiv.
- Force new pages
- Kada su praznine popunjene, sledeće alokacije moraju doći iz novih stranica dodatih zoni.
- Sveže stranice znače da će objekti biti grupisani zajedno, a ne razbacani po staroj fragmentisanoj memoriji.
- To napadaču daje mnogo bolju kontrolu nad susedima.
- Place attacker objects
- Napadač sada ponovo izvodi spray, kreirajući mnogo objekata pod svojom kontrolom u tim novim stranicama.
- Ti objekti su predvidljivi po veličini i poziciji (pošto svi pripadaju istoj zoni).
- Free a controlled object (make a gap)
- Napadač namerno free-uje jedan od svojih objekata.
- Time se stvara „rupa” u heap-u koju će allocator kasnije ponovo iskoristiti za sledeću alokaciju te veličine.
- Victim object lands in the hole
- Napadač izaziva kernel da alocira victim objekat (onaj koji želi da korumpira).
- Pošto je rupa prvi dostupan slot u freelist-u, victim se postavlja tačno na mesto gde je napadač oslobodio svoj objekat.
- Overflow / UAF into victim
- Sada napadač ima objekate pod svojom kontrolom oko victima.
- Prelivanjem iz jednog od sopstvenih objekata (ili ponovnim korišćenjem freed objekta), može pouzdano prepisati polja victim objekta sa izabranim vrednostima.
Zašto ovo radi:
- Predvidljivost zone allocator-a: alokacije iste veličine uvek dolaze iz iste zone.
- Freelist behavior: nove alokacije ponovo koriste najskorije freed chunk-ove prve.
- Heap sprays: napadač popunjava memoriju predvidljivim sadržajem i kontroliše raspored.
- Krajnji rezultat: napadač kontroliše gde se victim objekat nalazi i koji podaci mu stoje pored.
Modern Kernel Heap (iOS 15+/A12+ SoCs)
Apple je ojačao allocator i učinio heap grooming mnogo težim:
1. From Classic kalloc to kalloc_type
- Pre: postojala je jedna
kalloc.<size>zona za svaku veličinsku klasu (16, 32, 64, … 1280, itd.). Bilo koji objekat te veličine bio je postavljen tamo → objekti napadača mogli su se naći pored privilegovanih kernel objekata. - Sada:
- Kernel objekti se alociraju iz typed zones (
kalloc_type). - Svaki tip objekta (npr.
ipc_port_t,task_t,OSString,OSData) ima svoju posvećenu zonu, čak i ako su iste veličine. - Mapiranje između tipa objekta ↔ zone generiše se iz kalloc_type sistema u vreme kompajliranja.
Napadač više ne može garantovati da kontrolisani podaci (OSData) završe pored osetljivih kernel objekata (task_t) iste veličine.
2. Slabs and Per-CPU Caches
- Heap je podeljen na slabs (stranice memorije podeljene u fiksne chunk-ove za tu zonu).
- Svaka zona ima per-CPU cache da smanji contenton.
- Putanja alokacije:
- Pokušaj per-CPU cache-a.
- Ako je prazan, uzmi iz global freelist-a.
- Ako je freelist prazan, alociraj novi slab (jedna ili više stranica).
- Prednost: ova decentralizacija čini heap sprays manje determinističkim, pošto alokacije mogu biti zadovoljene iz cache-a različitih CPU-a.
3. Randomization inside zones
- Unutar zone, oslobodjeni elementi se ne vraćaju jednostavnim FIFO/LIFO redosledom.
- Moderni XNU koristi encoded freelist pointers (safe-linking stil kao Linux, uvedeno oko iOS 14).
- Svaki freelist pointer je XOR-encoded sa per-zone tajnim cookie-jem.
- Ovo sprečava napadače da fabrikuju lažni freelist pointer ako dobiju write primitive.
- Neke alokacije su randomizovane u postavljenju unutar slaba, pa spray ne garantuje susedstvo.
4. Guarded Allocations
- Određeni kritični kernel objekti (npr. credentials, task strukture) alociraju se u guarded zones.
- Te zone ubacuju guard pages (nemapirane stranice) između slabs-a ili koriste redzones oko objekata.
- Bilo koji overflow u guard page izaziva fault → trenutni panic umesto tihe korupcije.
5. Page Protection Layer (PPL) and SPTM
- Čak i ako kontrolišete freed objekat, ne možete modifikovati svu kernel memoriju:
- PPL (Page Protection Layer) nameće da određeni regioni (npr. code signing podaci, entitlements) budu read-only čak i za sam kernel.
- Na A15/M2+ uređajima, ovu ulogu zamenjuju/pojačavaju SPTM (Secure Page Table Monitor) + TXM (Trusted Execution Monitor).
- Ovi hardverski sprovedeni slojevi znače da napadači ne mogu iz jednog heap korupcije preći na arbitrarno patchovanje kritičnih security struktura.
- (Dodato / Pojačano): takođe se koristi PAC (Pointer Authentication Codes) u kernelu za zaštitu pointera (posebno funkcijskih pointera, vtable-ova) tako da njihovo fabrikovanje ili korupcija postaje teža.
- (Dodato / Pojačano): zone mogu nametnuti zone_require / zone enforcement, tj. da objekat koji je free-ovan može biti vraćen samo kroz svoju ispravnu typed zonu; nevažeći cross-zone free može izazvati panic ili biti odbijen. (Apple ovo aludira u svojim postovima o memory safety)
6. Large Allocations
- Ne sve alokacije prolaze kroz
kalloc_type. - Veći zahtevi (iznad ~16 KB) zaobilaze typed zones i služe se direktno iz kernel VM (kmem) preko page alokacija.
- Oni su manje predvidljivi, ali i manje eksploatabilni, pošto ne dele slabove sa drugim objektima.
7. Allocation Patterns Attackers Target
Čak i sa ovim zaštitama, napadači i dalje ciljaju:
- Reference count objects: ako možete manipulirati retain/release brojačima, možete izazvati use-after-free.
- Objects with function pointers (vtables): korumpovanje ovih i dalje daje kontrolu toka izvršavanja.
- Shared memory objects (IOSurface, Mach ports): i dalje su mete jer povezuju user ↔ kernel.
Ali — za razliku od pre — ne možete samo spray-ovati OSData i očekivati da bude pored task_t. Potrebni su type-specific bugs ili info leaks da bi se uspelo.
Example: Allocation Flow in Modern Heap
Pretpostavimo da userspace pozove u IOKit da alocira OSData objekat:
- Type lookup →
OSDatamapira se nakalloc_type_osdatazonu (size 64 bytes). - Check per-CPU cache for free elements.
- Ako pronađeno → vrati jedan.
- Ako je prazno → idi na global freelist.
- Ako je freelist prazan → alociraj novi slab (page od 4KB → 64 chunk-a od po 64 bytes).
- Return chunk to caller.
Freelist pointer protection:
- Svaki freed chunk čuva adresu sledećeg slobodnog chunk-a, ali enkodiranu sa tajnim ključem.
- Overwriting tog polja sa podacima napadača neće raditi osim ako ne znate ključ.
Comparison Table
| Feature | Old Heap (Pre-iOS 15) | Modern Heap (iOS 15+ / A12+) |
|---|---|---|
| Allocation granularity | Fixed size buckets (kalloc.16, kalloc.32, etc.) | Size + type-based buckets (kalloc_type) |
| Placement predictability | High (same-size objects side by side) | Low (same-type grouping + randomness) |
| Freelist management | Raw pointers in freed chunks (easy to corrupt) | Encoded pointers (safe-linking style) |
| Adjacent object control | Easy via sprays/frees (feng shui predictable) | Hard — typed zones separate attacker objects |
| Kernel data/code protections | Few hardware protections | PPL / SPTM protect page tables & code pages, and PAC protects pointers |
| Allocation reuse validation | None (freelist pointers raw) | zone_require / zone enforcement |
| Exploit reliability | High with heap sprays | Much lower, requires logic bugs or info leaks |
| Large allocations handling | All small allocations managed equally | Large ones bypass zones → handled via VM |
Modern Userland Heap (iOS, macOS — type-aware / xzone malloc)
U novijim Apple OS verzijama (posebno iOS 17+), Apple je uveo sigurniji userland allocator, xzone malloc (XZM). Ovo je user-space analog kernel-ovog kalloc_type, primenjujući type awareness, izolaciju metadata i memory tagging zaštite.
Goals & Design Principles
- Type segregation / type awareness: grupisanje alokacija po tipu ili upotrebi (pointer vs data) kako bi se sprečilo type confusion i cross-type reuse.
- Metadata isolation: odvajanje heap metadata (npr. free lists, size/state bitovi) od payload-a objekata, tako da OOB upisi manje verovatno korumpuju metadata.
- Guard pages / redzones: umetanje nemapiranih stranica ili padding-a oko alokacija da se uhvate overflows.
- Memory tagging (EMTE / MIE): radi u saradnji sa hardware tagging-om da detektuje use-after-free, OOB i nevažeće pristupe.
- Scalable performance: održavanje malog overhead-a, izbegavanje prekomerne fragmentacije i podrška velikom broju alokacija po sekundi sa malim latencijama.
Architecture & Components
Ispod su glavni elementi xzone allocatora:
Segment Groups & Zones
- Segment groups particionišu address space po kategorijama upotrebe: npr.
data,pointer_xzones,data_large,pointer_large. - Svaka segment grupa sadrži segments (VM opsege) koji hostuju alokacije za tu kategoriju.
- Povezano sa svakim segmentom je metadata slab (odvojen VM region) koji čuva metadata (npr. free/used bitove, size class informacije) za taj segment. Ova out-of-line (OOL) metadata osigurava da metadata nije pomešana sa payload-om objekata, smanjujući mogućnost korupcije od overflow-a.
- Segmenti su podeljeni na chunks (slices) koji se dalje dele na blocks (alokacione jedinice). Chunk je vezan za specifičnu size class i segment group (tj. svi block-ovi u chunk-u dele istu veličinu i kategoriju).
- Za male/srednje alokacije koristi se fiksna veličina chunk-ova; za velike/ogromne, chunk se može mapirati zasebno.
Chunks & Blocks
- Chunk je region (često nekoliko stranica) posvećen alokacijama jedne size class unutar grupе.
- Unutar chunk-a, blocks su slotovi dostupni za alokacije. Freed blocks se prate preko metadata slab-a — npr. preko bitmap-a ili free list-a koji su smešteni out-of-line.
- Između chunk-ova (ili unutar njih) mogu se umetnuti guard slices / guard pages (npr. nemapirane sličice) da uhvate out-of-bounds upise.
Type / Type ID
- Svaka lokacija alokacije (ili poziv malloc/calloc itd.) je povezana sa type identifier-om (
malloc_type_id_t) koji kodira kakav tip objekta se alocira. Taj type ID se prosleđuje allocator-u, koji ga koristi da izabere koju zonu/segment da servisira. - Zbog toga, čak i ako dve alokacije imaju istu veličinu, mogu ići u potpuno različite zone ako im tipovi ne odgovaraju.
- U ranim iOS 17 verzijama, nisu svi API-ji (npr. CFAllocator) bili potpuno type-aware; Apple je adresirao neke od tih slabosti u iOS 18.
Allocation & Freeing Workflow
Evo high-level toka kako alokacija i dealokacija rade u xzone:
- malloc / calloc / realloc / typed alloc se poziva sa veličinom i type ID-om.
- Allocator koristi type ID da izabere odgovarajući segment group / zonu.
- Unutar te zone/segmenta traži chunk koji ima slobodne block-ove tražene veličine.
- Može proveriti local caches / per-thread pools ili free block lists iz metadata.
- Ako nema slobodnog block-a, može alocirati novi chunk u toj zoni.
- Metadata slab se ažurira (free bit se briše, bookkeeping).
- Ako je memory tagging (EMTE) u igri, vraćeni block dobija tag, i metadata se ažurira da označi da je block „live”.
- Kada se pozove
free():
- Block se označava kao freed u metadata (preko OOL slab-a).
- Block može biti stavljen u free list ili pooled za ponovnu upotrebu.
- Opcionalno, sadržaj block-a može biti očišćen ili poison-ovan da smanji data leaks ili UAF eksploataciju.
- Hardverski tag povezan sa block-om može biti invalidiran ili re-tagovan.
- Ako ceo chunk postane slobodan (svi block-ovi freed), allocator može reclaim taj chunk (unmap-ovati ga ili vratiti OS-u) pod memorijskim pritiskom.
Security Features & Hardening
Ovo su odbrane ugrađene u moderni userland xzone:
| Feature | Purpose | Notes |
|---|---|---|
| Metadata decoupling | Prevent overflow from corrupting metadata | Metadata živi u odvojenom VM regionu (metadata slab) |
| Guard pages / unmapped slices | Catch out-of-bounds writes | Pomaže detektovati buffer overflows umesto tihog korumpiranja susednih block-ova |
| Type-based segregation | Prevent cross-type reuse & type confusion | Čak i iste-size alokacije iz različitih tipova idu u različite zone |
| Memory Tagging (EMTE / MIE) | Detect invalid access, stale references, OOB, UAF | xzone radi u tandemu sa hardverskim EMTE u synchronous modu (“Memory Integrity Enforcement”) |
| Delayed reuse / poisoning / zap | Reduce chance of use-after-free exploitation | Freed block-ovi mogu biti poison-ovani, zero-ovani ili karantinisani pre ponovne upotrebe |
| Chunk reclamation / dynamic unmapping | Reduce memory waste and fragmentation | Cela chunk-ova može biti unmap-ovana kada je neiskorišćena |
| Randomization / placement variation | Prevent deterministic adjacency | Block-ovi u chunk-u i izbor chunk-a mogu imati randomizovane aspekte |
| Segregation of “data-only” allocations | Separate allocations that don’t store pointers | Razdvaja alokacije koje ne čuvaju pointer-e, smanjujući kontrolu napadača nad metadata ili kontrolnim poljima |
Interaction with Memory Integrity Enforcement (MIE / EMTE)
- Apple-ov MIE (Memory Integrity Enforcement) je hardware + OS framework koji dovodi Enhanced Memory Tagging Extension (EMTE) u uvek-uključen, sinhroni režim preko glavnih attack surface-a.
- xzone allocator je temelj MIE u user space: alokacije preko xzone dobijaju tagove, a pristupi se proveravaju hardverom.
- U MIE, allocator, dodela tagova, upravljanje metadata i enforcement poverljivosti tag-ova su integrisani da osiguraju da greške u memoriji (npr. stale reads, OOB, UAF) budu uhvaćene odmah, a ne iskorišćene kasnije.
- Ako želite, mogu takođe generisati cheat-sheet ili dijagram xzone internals za vašu knjigu. Da li želite da to uradim sledeće?
- :contentReference[oai:20]{index=20}
(Old) Physical Use-After-Free via IOSurface
Ghidra Install BinDiff
Download BinDiff DMG from https://www.zynamics.com/bindiff/manual and install it.
Open Ghidra with ghidraRun and go to File –> Install Extensions, press the add button and select the path /Applications/BinDiff/Extra/Ghidra/BinExport and click OK and isntall it even if there is a version mismatch.
Using BinDiff with Kernel versions
- Go to the page https://ipsw.me/ and download the iOS versions you want to diff. These will be
.ipswfiles. - Decompress until you get the bin format of the kernelcache of both
.ipswfiles. You have information on how to do this on:
macOS Kernel Extensions & Kernelcache
- Open Ghidra with
ghidraRun, create a new project and load the kernelcaches. - Open each kernelcache so they are automatically analyzed by Ghidra.
- Then, on the project Window of Ghidra, right click each kernelcache, select
Export, select formatBinary BinExport (v2) for BinDiffand export them. - Open BinDiff, create a new workspace and add a new diff indicating as primary file the kernelcache that contains the vulnerability and as secondary file the patched kernelcache.
Finding the right XNU version
If you want to check for vulnerabilities in a specific version of iOS, you can check which XNU release version the iOS version uses at [https://www.theiphonewiki.com/wiki/kernel]https://www.theiphonewiki.com/wiki/kernel).
For example, the versions 15.1 RC, 15.1 and 15.1.1 use the version Darwin Kernel Version 21.1.0: Wed Oct 13 19:14:48 PDT 2021; root:xnu-8019.43.1~1/RELEASE_ARM64_T8006.
JSKit-Based Safari Chains and PREYHUNTER Stagers
Renderer RCE abstraction with JSKit
- Reusable entry: Recent in-the-wild chains abused a WebKit JIT bug (patched as CVE-2023-41993) purely to gain JavaScript-level arbitrary read/write. The exploit immediately pivots into a purchased framework called JSKit, so any future Safari bug only needs to deliver the same primitive.
- Version abstraction & PAC bypasses: JSKit bundles support for a wide range of iOS releases together with multiple, selectable Pointer Authentication Code bypass modules. The framework fingerprints the target build, selects the appropriate PAC bypass logic, and verifies every step (primitive validation, shellcode launch) before progressing.
- Manual Mach-O mapping: JSKit parses Mach-O headers directly from memory, resolves the symbols it needs inside dyld-cached images, and can manually map additional Mach-O payloads without writing them to disk. This keeps the renderer process in-memory only and evades code-signature checks tied to filesystem artifacts.
- Portfolio model: Debug strings such as “exploit number 7” show that the suppliers maintain multiple interchangeable WebKit exploits. Once the JS primitive matches JSKit’s interface, the rest of the chain is unchanged across campaigns.
Kernel bridge: IPC UAF -> code-sign bypass pattern
- Kernel IPC UAF (CVE-2023-41992): The second stage, still running inside the Safari context, triggers a kernel use-after-free in IPC code, re-allocates the freed object from userland, and abuses the dangling pointers to pivot into arbitrary kernel read/write. The stage also reuses PAC bypass material previously computed by JSKit instead of re-deriving it.
- Code-signing bypass (CVE-2023-41991): With kernel R/W available, the exploit patches the trust cache / code-signing structures so unsigned payloads execute as
system. The stage then exposes a lightweight kernel R/W service to later payloads. - Composed pattern: This chain demonstrates a reusable recipe that defenders should expect going forward:
WebKit renderer RCE -> kernel IPC UAF -> kernel arbitrary R/W -> code-sign bypass -> unsigned system stager
PREYHUNTER helper & watcher modules
-
Watcher anti-analysis: Dedicated watcher binarni fajl neprekidno profilira uređaj i prekida kill-chain kada se detektuje research environment. On proverava
security.mac.amfi.developer_mode_status, prisustvodiagnosticdkonzole, lokalizacijeUSiliIL, tragove jailbreak-a kao što je Cydia, procese poputbash,tcpdump,frida,sshdilicheckrain, mobilne AV aplikacije (McAfee, AvastMobileSecurity, NortonMobileSecurity), prilagođena HTTP proxy podešavanja i prilagođene root CA. Neuspeh bilo koje provere blokira dalju isporuku payload-a. -
Helper surveillance hooks: Helper komponenta komunicira sa ostalim fazama preko
/tmp/helper.sock, a zatim učitava setove hook-ova nazvane DMHooker i UMHooker. Ovi hook-ovi tapšu VOIP audio puteve (snimci se čuvaju pod/private/var/tmp/l/voip_%lu_%u_PART.m4a), implementiraju sistemski keylogger, fotografišu bez UI i hook-uju SpringBoard kako bi suzbili notifikacije koje bi te akcije normalno izazvale. Helper dakle deluje kao stealth validacioni + light-surveillance sloj pre nego što se otpuste teži implantati poput Predator-a. -
HiddenDot indicator suppression in SpringBoard: Uz kernel-level code injection, Predator hook-uje
SBSensorActivityDataProvider._handleNewDomainData:(tačka agregacije za sensor activity). Hook zeruje Objective-Cselfpointer (x0) tako da poziv postaje[nil _handleNewDomainData:newData], odbacujući camera/mic update-ove i suzbijajući i green i orange dot indikatore. -
Mach exception-based hooking flow (DMHooker): Hook-ovi se implementiraju preko
EXC_BREAKPOINT+ exception portova, zatimthread_set_statemutira registre i izvršenje se nastavlja. Povratni kod2znači “continue with modified thread state.” -
PAC-aware redirection for camera access checks: U
mediaserverd, pattern-scan (npr.memmem) locira privatnu rutinu blizuFigVideoCaptureSourceCreateWithSourceInfounutarCMCapture.framework. Hook vraća3da preusmeri koristeći pre-signed PAC cached return address, zadovoljavajući PAC dok zaobilazi proveru. -
VoIP capture pipeline in
mediaserverd: Hook-ujeAudioConverterNewiAudioConverterConvertComplexBuffer+52da pristupe buffer-ima, inferiraju sample rate iz veličina buffera, konvertuju float32 PCM → int16 koristeći NEON, downmix-uju 4-channel u stereo i persist-uju putemExtAudioFileWrite(). VoIP modul sam po sebi ne suzbija indikatore, pa operateri moraju posebno omogućiti HiddenDot.
WebKit DFG Store-Barrier UAF + ANGLE PBO OOB (iOS 26.1)
Webkit Dfg Store Barrier Uaf Angle Oob
iMessage/Media Parser Zero-Click Chains
Imessage Media Parser Zero Click Coreaudio Pac Bypass
References
- https://www.jamf.com/blog/predator-spyware-ios-recording-indicator-bypass-analysis/
- Google Threat Intelligence – Intellexa zero-day exploits continue
Tip
Učite i vežbajte AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.


