iOS Exploiting
Reading time: 52 minutes
tip
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
Мітігації експлойтів iOS
1. Code Signing / Runtime Signature Verification
Introduced early (iPhone OS → iOS) Це один із фундаментальних захистів: весь виконуваний код (apps, dynamic libraries, JIT-ed code, extensions, frameworks, caches) повинен бути криптографічно підписаний сертифікатним ланцюжком, корінь якого — Apple’s trust. Під час виконання, перед завантаженням бінарника в пам’ять (або перед виконанням переходів через певні межі), система перевіряє його підпис. Якщо код змінено (bit-flipped, patched) або він непідписаний, завантаження зазнає невдачі.
- Thwarts: the “classic payload drop + execute” stage in exploit chains; arbitrary code injection; modifying an existing binary to insert malicious logic.
- Mechanism detail:
- The Mach-O loader (and dynamic linker) checks code pages, segments, entitlements, team IDs, and that the signature covers the file’s contents.
- For memory regions like JIT caches or dynamically generated code, Apple enforces that pages be signed or validated via special APIs (e.g.
mprotect
with code-sign checks). - The signature includes entitlements and identifiers; the OS enforces that certain APIs or privileged capabilities require specific entitlements that cannot be forged.
Example
Припустимо, експлойт отримує виконання коду в процесі і намагається записати shellcode в heap і перейти до нього. На iOS ця сторінка має бути позначена як executable **і** відповідати обмеженням code-signature. Оскільки shellcode не підписано сертифікатом Apple, перехід не виконується або система відмовляє у наданні цій ділянці пам’яті executable доступу.2. CoreTrust
Introduced around iOS 14+ era (or gradually in newer devices / later iOS) CoreTrust — підсистема, яка виконує runtime signature validation бінарників (включно з системними і юзерськими) проти Apple’s root certificate, замість того щоб покладатися на кешовані userland trust stores.
- Thwarts: post-install tampering of binaries, jailbreaking techniques that try to swap or patch system libraries or user apps; tricking the system by replacing trusted binaries with malicious counterparts.
- Mechanism detail:
- Instead of trusting a local trust database or certificate cache, CoreTrust fetches or refers to Apple’s root directly or verifies intermediate certificates in a secure chain.
- It ensures that modifications (e.g. in the filesystem) to existing binaries are detected and rejected.
- It ties entitlements, team IDs, code signing flags, and other metadata to the binary at load time.
Example
Jailbreak може спробувати замінити `SpringBoard` або `libsystem` на патчений варіант, щоб отримати persistence. Але коли loader системи або CoreTrust перевіряє підпис, він виявляє невідповідність signature (або змінені entitlements) і відмовляє у виконанні.3. Data Execution Prevention (DEP / NX / W^X)
Introduced in many OSes earlier; iOS had NX-bit / w^x for a long time DEP забезпечує, що сторінки, позначені writable (для даних), є non-executable, а сторінки, позначені executable, є non-writable. Ви не можете просто записати shellcode в heap або stack і виконати його.
- Thwarts: direct shellcode execution; classic buffer-overflow → jump to injected shellcode.
- Mechanism detail:
- The MMU / memory protection flags (via page tables) enforce the separation.
- Any attempt to mark a writable page executable triggers a system check (and is either forbidden or requires code-sign approval).
- In many cases, making pages executable requires going through OS APIs that enforce additional constraints or checks.
Example
Переповнення записує shellcode в heap. Атакуючий виконує `mprotect(heap_addr, size, PROT_EXEC)`, щоб зробити її executable. Але система відмовляє або валідовує, що нова сторінка має пройти code-sign constraints (чого shellcode не може).4. Address Space Layout Randomization (ASLR)
Introduced in iOS ~4–5 era (roughly iOS 4–5 timeframe) ASLR рандомізує базові адреси ключових регіонів пам’яті: libraries, heap, stack тощо, при кожному запуску процесу. Адреси gadget-ів рухаються між запусками.
- Thwarts: hardcoding gadget addresses for ROP/JOP; static exploit chains; blind jumping to known offsets.
- Mechanism detail:
- Each loaded library / dynamic module is rebased at a randomized offset.
- Stack and heap base pointers are randomized (within certain entropy limits).
- Sometimes other regions (e.g. mmap allocations) are also randomized.
- Combined with information-leak mitigations, it forces the attacker to first leak an address or pointer to discover base addresses at runtime.
Example
ROP-ланцюг очікує gadget за `0x….lib + offset`. Але оскільки `lib` підвантажується з різним зміщенням щораз, захардкоджений ланцюг не спрацює. Експлойт повинен спочатку leak базову адресу модуля, щоб порахувати адреси gadget-ів.5. Kernel Address Space Layout Randomization (KASLR)
Introduced in iOS ~ (iOS 5 / iOS 6 timeframe) Аналогічно до user ASLR, KASLR рандомізує базу kernel text та інших kernel-структур під час завантаження (boot).
- Thwarts: kernel-level exploits that rely on fixed location of kernel code or data; static kernel exploits.
- Mechanism detail:
- On each boot, the kernel’s base address is randomized (within a range).
- Kernel data structures (like
task_structs
,vm_map
, etc.) may also be relocated or offset. - Attackers must first leak kernel pointers or use information disclosure vulnerabilities to compute offsets before hijacking kernel structures or code.
Example
Локальна вразливість намагається пошкодити kernel function pointer (наприклад у `vtable`) на `KERN_BASE + offset`. Але оскільки `KERN_BASE` невідомий, атакуючий повинен спочатку leak його (наприклад через read-примітив), щоб коректно порахувати адресу для корупції.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) постійно моніторить цілісність kernel text pages (через hash або checksum). Якщо виявить підтасовку (patches, inline hooks, code modifications) поза дозволеними вікнами, він викликає kernel panic або перезавантаження.
- Thwarts: persistent kernel patching (modifying kernel instructions), inline hooks, static function overwrites.
- Mechanism detail:
- A hardware or firmware module monitors the kernel text region.
- It periodically or on-demand re-hashes the pages and compares against expected values.
- If mismatches occur outside benign update windows, it panics the device (to avoid persistent malicious patch).
- Attackers must either avoid detection windows or use legitimate patch paths.
Example
Експлойт намагається пропатчити пролог функції ядра (наприклад `memcmp`), щоб перехоплювати виклики. Але KPP помічає, що hash code page вже не відповідає очікуваному значенню, і викликає kernel panic, крашуючи пристрій до того, як патч усталиться.7. Kernel Text Read‐Only Region (KTRR)
Introduced in modern SoCs (post ~A12 / newer hardware) KTRR — hardware-enforced механізм: коли kernel text фіксується рано під час boot, він стає read-only з EL1 (kernel), що запобігає подальшим записам у code pages.
- Thwarts: any modifications to kernel code after boot (e.g. patching, in-place code injection) at EL1 privilege level.
- Mechanism detail:
- During boot (in secure/bootloader stage), the memory controller (or a secure hardware unit) marks the physical pages containing kernel text as read-only.
- Even if an exploit gains full kernel privileges, it cannot write to those pages to patch instructions.
- To modify them, the attacker must first compromise the boot chain, or subvert KTRR itself.
Example
Експлойт піднімає привілеї до EL1 і пише trampoline у kernel function (наприклад у syscall handler). Але оскільки сторінки заблоковано в режимі read-only через KTRR, запис не вдається (або викликає fault), і патч не застосовується.8. Pointer Authentication Codes (PAC)
Introduced with ARMv8.3 (hardware), Apple beginning with A12 / iOS ~12+
- PAC — hardware-фіча, введена в ARMv8.3-A, для виявлення підтасовки значень pointer-ів (return addresses, function pointers, certain data pointers) шляхом вбудовування невеликого криптографічного підпису (“MAC”) в невикористані верхні біти pointer-а.
- Підпис (“PAC”) обчислюється над значенням pointer-а плюс modifier (контекстне значення, наприклад stack pointer або інші дані). Таким чином той самий pointer у різних контекстах матиме різний PAC.
- При використанні, перед роздереференсом або переходом через pointer, інструкція authenticate перевіряє PAC. Якщо він валідний, PAC знімається і отримується чистий pointer; якщо ні — pointer “псується” (poisoned) або викликається fault.
- Ключі, які використовуються для генерації/валідації PAC, зберігаються в привілейованих регістрах (EL1, kernel) і недоступні з user mode.
- Оскільки не всі 64 біти pointer-а використовуються в багатьох системах (наприклад 48-бітна адресація), верхні біти є “вільними” і можуть містити PAC без зміни ефективної адреси.
Architectural Basis & Key Types
-
ARMv8.3 вводить п’ять 128-bit ключів (кожен реалізовано через два 64-bit системні регістри) для pointer authentication.
-
APIAKey — для instruction pointers (domain “I”, key A)
-
APIBKey — другий ключ для instruction pointers (domain “I”, key B)
-
APDAKey — для data pointers (domain “D”, key A)
-
APDBKey — для data pointers (domain “D”, key B)
-
APGAKey — “generic” ключ, для підпису non-pointer даних або інших generic використань
-
Ці ключі зберігаються в привілейованих системних регістрах (доступні тільки на EL1/EL2 тощо), недоступні з user mode.
-
PAC обчислюється криптографічною функцією (ARM пропонує QARMA як алгоритм) з використанням:
- Значення pointer-а (канонічна частина)
- modifier (контекстне значення, як-сілт)
- Секретний ключ
- Деяких внутрішніх механізмів змішування Якщо обчислений PAC відповідає тому, що зберігається у верхніх бітах pointer-а, автентифікація успішна.
Instruction Families
Конвенція іменування: PAC / AUT / XPAC, потім літери домену.
PACxx
інструкції підписують pointer і вставляють PACAUTxx
інструкції автентифікують + знімають (перевіряють і видаляють PAC)XPACxx
інструкції знімають PAC без перевірки
Domains / суфікси:
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 |
There are specialized / alias forms:
PACIASP
is shorthand forPACIA X30, SP
(sign the link register using SP as modifier)AUTIASP
isAUTIA X30, SP
(authenticate link register with SP)- Combined forms like
RETAA
,RETAB
(authenticate-and-return) orBLRAA
(authenticate & branch) exist in ARM extensions / compiler support. - Also zero-modifier variants:
PACIZA
/PACIZB
where the modifier is implicitly zero, etc.
Modifiers
Головна мета modifier — зв’язати PAC з конкретним контекстом, щоб те саме підписане значення адреси в різних контекстах давало різні PAC-и. Це запобігає простому повторному використанню pointer-а між кадрами або об’єктами. Це як додавання salt до хешу.
Отже:
- modifier — це контекстне значення (інший регістр), яке змішується в обчисленні PAC. Типові вибори: stack pointer (
SP
), frame pointer або якийсь object ID. - Використання SP як modifier поширене для підписування return address: PAC зв’язується з конкретним stack frame. Якщо спробувати повторно використати LR в іншому фреймі, modifier зміниться і валідація PAC провалиться.
- Те саме значення pointer-а, підписане з різними modifiers, дає різні PAC-и.
- Modifier не обов’язково має бути секретним, але бажано, щоб ним не керував атакувальник.
- Для випадків, де для підписання або перевірки pointer-а немає змістовного modifier-а, використовуються форми з нульовим або імпліцитним константним modifier-ом.
Apple / iOS / XNU Customizations & Observations
- Apple’s PAC імплементація включає перебірні diversifiers на кожен boot, тому ключі або tweak-и змінюються при кожному завантаженні, що ускладнює повторне використання між завантаженнями.
- Вони також містять cross-domain mitigations, тож PAC, підписані в user mode, не можуть легко бути використані в kernel mode тощо.
- На Apple M1 / Apple Silicon інженерний зворотний інжиніринг показав, що існує дев’ять типів modifier-ів та Apple-специфічні системні регістри для контролю ключів.
- Apple використовує PAC у багатьох kernel-підсистемах: підписування return address, інтегритет pointer-ів в kernel data, підписані thread contexts тощо.
- Google Project Zero показав, що при сильних примітивах читання/запису пам’яті в kernel можна було підробити kernel PACs (для A keys) на A12-era пристроях, але Apple закрила багато з тих шляхів.
- В системі Apple деякі ключі є глобальними для ядра, тоді як процеси користувача можуть отримувати per-process випадковість ключів.
PAC Bypasses
- Kernel-mode PAC: theoretical vs real bypasses
- Оскільки kernel PAC ключі і логіка жорстко контрольовані (привілейовані регістри, diversifiers, доменна ізоляція), підробити довільні підписані kernel pointer-и дуже важко.
- Azad's 2020 "iOS Kernel PAC, One Year Later" показав, що в iOS 12-13 він знайшов кілька часткових обхідних шляхів (signing gadgets, reuse of signed states, unprotected indirect branches), але не загального універсального bypass. bazad.github.io
- Apple’s "Dark Magic" кастомізації ще більше звужують експлуатовані поверхні (domain switching, per-key enabling bits). i.blackhat.com
- Існує відомий kernel PAC bypass CVE-2023-32424 на Apple silicon (M1/M2), описаний Zecao Cai та ін. i.blackhat.com
- Але ці обходи часто залежать від дуже специфічних gadget-ів або багів реалізації; вони не є загальними.
Отже kernel PAC вважається дуже стійким, хоча й не ідеальним.
- User-mode / runtime PAC bypass techniques
Ці обходи більш поширені і експлуатують недоліки у застосуванні PAC або в runtime/dynamic linking фреймворках. Нижче класи з прикладами.
2.1 Shared Cache / A key issues
- dyld shared cache — великий попередньо лінкований blob системних frameworks і бібліотек. Оскільки він широко спільний, function pointers всередині shared cache часто "pre-signed" і використовуються багатьма процесами. Атакувальники орієнтуються на ці вже-підписані pointer-и як на "PAC oracles".
- Деякі методи обходу намагаються витягти або повторно використати A-key підписані pointer-и зі shared cache і об’єднати їх з gadget-ами.
- Доповідь "No Clicks Required" описує побудову oracle над shared cache для виведення відносних адрес і комбінування цього з підписаними pointer-ами, щоб обійти PAC. saelo.github.io
- Також імпорти function pointers з shared libraries у userspace інколи виявлялися недостатньо захищеними PAC, що дозволяло атакуючому отримувати function pointers без зміни їх підпису. (Project Zero bug entry) bugs.chromium.org
2.2 dlsym(3) / dynamic symbol resolution
- Відомий обхід — викликати
dlsym()
щоб отримати вже підписаний function pointer (підписаний A-key, diversifier zero) і потім його використати. Оскількиdlsym
повертає легітимно підписаний pointer, його використання обходить необхідність підробляти PAC. - Epsilon's blog детально описує, як деякі обходи використовують це: виклик
dlsym("someSym")
дає підписаний pointer, який можна використати для indirect calls. blog.epsilon-sec.com - Synacktiv's "iOS 18.4 --- dlsym considered harmful" описує баг: деякі символи, резольвлені через
dlsym
на iOS 18.4, повертають pointer-и, які некоректно підписані (або з баговими diversifiers), що дає можливість обійти PAC. Synacktiv - Логіка в dyld для dlsym включає: коли
result->isCode
, вони підписують повернутий pointer через__builtin_ptrauth_sign_unauthenticated(..., key_asia, 0)
, тобто з контекстом нуль. blog.epsilon-sec.com
Отже, dlsym
часто є вектором для user-mode PAC обходів.
2.3 Other DYLD / runtime relocations
- DYLD loader і логіка динамічної релокації складні і іноді тимчасово маплять сторінки як read/write для виконання релокацій, потім знову роблять їх read-only. Атакувальники експлуатують ці вікна. Synacktiv описує "Operation Triangulation", таймінговий bypass PAC через динамічні релокації. Synacktiv
- DYLD сторінки тепер захищені SPRR / VM_FLAGS_TPRO (деякі прапори захисту для dyld). Але в раніших версіях захисти були слабкіші. Synacktiv
- У WebKit exploit-ланцюгах DYLD loader часто стає ціллю для PAC обходів. Слайди згадують, що багато PAC-обходів були спрямовані на DYLD loader (через релокацію, interposer hooks). Synacktiv
2.4 NSPredicate / NSExpression / ObjC / SLOP
- В userland exploit-ланцюгах Objective-C runtime методи як
NSPredicate
,NSExpression
абоNSInvocation
використовуються для контрабанди викликів контролю без очевидного форджингу pointer-ів. - На старих iOS (до PAC) експлойт використовував fake NSInvocation об’єкти, щоб викликати довільні селектори на контрольованій пам’яті. З PAC техніка потребує модифікацій. Але SLOP (SeLector Oriented Programming) була розширена під PAC теж. Project Zero
- Початкова техніка SLOP дозволяла ланцюжити ObjC виклики створюючи фейкові invocations; обхід базувався на тому, що ISA або selector pointer-и іноді не були повністю захищені PAC. Project Zero
- В середовищах, де pointer authentication застосовується частково, методи / селектори / target pointer-и можуть не мати PAC-захисту, що дає простір для обходів.
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>Example</summary>
A buffer overflow overwrites a return address on the stack. The attacker writes the target gadget address but cannot compute the correct PAC. When the function returns, the CPU’s `AUTIA` instruction faults because the PAC mismatch. The chain fails.
Project Zero’s analysis on A12 (iPhone XS) showed how Apple’s PAC is used and methods of forging PACs if an attacker has a memory read/write primitive.
</details>
### 9. **Branch Target Identification (BTI)**
**Впроваджено в ARMv8.5 (пізніше апаратне забезпечення)**
BTI — апаратна можливість, яка перевіряє **непрямі цілі переходів**: при виконанні `blr` або непрямих викликів/стрибків ціль повинна починатися з **BTI landing pad** (`BTI j` або `BTI c`). Перехід у адреси гаджетів без такого лендінг-паду призводить до виключення.
Реалізація LLVM відзначає три варіанти інструкцій BTI і як вони відображаються на типах переходів.
| BTI Variant | Що дозволяє (для яких типів переходів) | Типове розміщення / випадок використання |
|-------------|----------------------------------------|-------------------------------|
| **BTI C** | Цілі непрямих переходів у стилі *call* (наприклад `BLR`, або `BR`, що використовує X16/X17) | Розміщується на вході функцій, які можуть викликатися непрямо |
| **BTI J** | Цілі переходів у стилі *jump* (наприклад `BR`, що використовується для tail calls) | Ставиться на початку блоків, доступних через jump tables або tail-calls |
| **BTI JC** | Працює як C і J одночасно | Може бути ціллю як call-, так і jump-переходів |
- В коді, скомпільованому з примусовою перевіркою branch target, компілятори вставляють інструкцію BTI (C, J або JC) в кожну дійсну ціль непрямого переходу (початки функцій або блоки, досяжні через стрибки), так щоб непрямі переходи вдались лише в ці місця.
- **Прямі переходи / виклики** (тобто фіксовані адреси `B`, `BL`) **не обмежуються** BTI. Припускається, що сторінки коду довірені й атакувальник не може їх змінити (тому прямі переходи вважаються безпечними).
- Також **RET / return** інструкції загалом не обмежуються BTI, оскільки адреси повернення захищені через PAC або механізми підписування повернень.
#### Механізм та контроль
- Коли CPU декодує **непрямий перехід (BLR / BR)** на сторінці, позначеній як «guarded / BTI-enabled», воно перевіряє, чи перша інструкція за адресою цілі є дійсною BTI (C, J або JC, як дозволено). Якщо ні — виникає **Branch Target Exception**.
- Кодування інструкції BTI спроектовано так, щоб пере-використовувати опкоді, раніше зарезервовані для NOPs (в попередніх версіях ARM). Тому бінарники з BTI сумісні в зворотному напрямку: на апаратурі без підтримки BTI ці інструкції поводяться як NOPs.
- Проходи компілятора, які додають BTI, вставляють їх лише там, де потрібно: у функціях, що можуть викликатися непрямо, або в базових блоках, які є ціллю стрибків.
- Деякі патчі та код LLVM показують, що BTI не вставляється для *усіх* базових блоків — лише для тих, які є потенційними цілями переходів (наприклад, з switch / jump tables).
#### Синергія BTI + PAC
PAC захищає значення вказівника (джерело) — гарантує, що ланцюжок непрямих викликів / повернень не був підроблений.
BTI гарантує, що навіть дійсний вказівник має спрямовуватися лише в правильно марковані точки входу.
Разом, атакувальнику потрібен як дійсний вказівник з коректним PAC, так і те, щоб ціль мала вставлений BTI. Це ускладнює побудову експлойт-ґаджетів.
#### Example
<details>
<summary>Example</summary>
An exploit tries to pivot into gadget at `0xABCDEF` that doesn’t start with `BTI c`. The CPU, upon executing `blr x0`, checks the target and faults because the instruction alignment doesn’t include a valid landing pad. Thus many gadgets become unusable unless they include BTI prefix.
</details>
### 10. **Privileged Access Never (PAN) & Privileged Execute Never (PXN)**
**Введено в пізніших розширеннях ARMv8 / підтримці iOS (для загартованого kernel)**
#### PAN (Privileged Access Never)
- **PAN** — це можливість, введена в **ARMv8.1-A**, яка забороняє **privileged code** (EL1 або EL2) **читати або записувати** пам’ять, позначену як **user-accessible (EL0)**, якщо PAN явно не вимкнено.
- Ідея: навіть якщо kernel скомпрометовано або обмануто, він не зможе довільно дереференсити user-space вказівники без попереднього *очищення* PAN, зменшуючи ризики експлойтів типу **`ret2usr`** або зловживань користувацькими буферами.
- Коли PAN увімкнено (PSTATE.PAN = 1), будь-яка привілейована інструкція load/store, яка звертається до віртуальної адреси, що “доступна на EL0”, викликає **permission fault**.
- Kernel, коли йому потрібно законно звертатися до user-space пам’яті (наприклад копіювання даних у/з user buffers), повинен **тимчасово вимкнути PAN** (або використати “unprivileged load/store” інструкції), щоб дозволити доступ.
- В Linux на ARM64 підтримка PAN була додана близько 2015 року: патчі ядра додали виявлення цієї можливості та замінили `get_user` / `put_user` тощо на варіанти, що очищують PAN при доступі до user memory.
**Ключова тонкість / обмеження / баг**
- Як зауважували Siguza та інші, баг специфікації (або неоднозначна поведінка) в дизайні ARM означає, що **execute-only user mappings** (`--x`) можуть **не викликати PAN**. Іншими словами, якщо user сторінка позначена як виконувана, але без дозволу на читання, спроба kernel читати її може обійти PAN, бо архітектура вважає “доступною на EL0” потребу в праві читання, а не тільки виконання. Це призводить до PAN bypass у певних конфігураціях.
- Через це, якщо iOS / XNU дозволяє execute-only user pages (як в деяких JIT або code-cache налаштуваннях), kernel може випадково читати з них навіть при увімкненому PAN. Це відома тонка область, яка може бути експлуатована в деяких ARMv8+ системах.
#### PXN (Privileged eXecute Never)
- **PXN** — це біт у page table entry (leaf або block), який вказує, що сторінка **неприпустима для виконання в привілейованому режимі** (тобто коли EL1 виконує код).
- PXN заважає kernel (або будь-якому privileged коду) переходити в або виконувати інструкції зі сторінок user-space навіть якщо контроль було відхилено. Це фактично перешкоджає перенаправленню керування на user-пам’ять на рівні kernel.
- У поєднанні з PAN це забезпечує:
1. Kernel не може (за замовчуванням) читати або записувати user-space дані (PAN)
2. Kernel не може виконувати user-space код (PXN)
- У форматі page table ARMv8 leaf entries мають біт `PXN` (а також `UXN` для unprivileged execute-never) в їхніх бітових атрибутах.
Отже навіть якщо kernel має пошкоджений function pointer, що вказує на user memory, спроба перейти туди викличе помилку через PXN.
#### Модель дозволів пам’яті та як PAN / PXN відображаються на бітах page table
Щоб зрозуміти, як PAN / PXN працюють, треба подивитися на модель трансляції й дозволів ARM (спрощено):
- Кожна сторінка або block entry має поля атрибутів, включаючи **AP[2:1]** для прав доступу (читання/запис, privileged vs unprivileged) та біти **UXN / PXN** для заборони виконання.
- Коли PSTATE.PAN = 1 (увімкнено), апарат примусово застосовує змінені семантики: привілейовані доступи до сторінок, позначених як “доступні EL0” (тобто user-accessible), заборонені (fault).
- Через описаний баг, сторінки, позначені тільки як виконувані (без права читання), можуть не вважатися “доступними EL0” в деяких реалізаціях і тим самим обходити PAN.
- Коли для сторінки встановлено біт PXN, навіть якщо запит на вибір інструкції походить з більш високого рівня привілеїв, виконання заборонено.
#### Використання PAN / PXN в загартованому OS kernel (наприклад iOS / XNU)
У дизайні загартованого ядра (як у Apple):
- Kernel вмикає PAN за замовчуванням (щоб привілейований код був обмежений).
- Шляхи, що легітимно потребують читання/запису user buffers (наприклад syscall buffer copy, I/O, read/write user pointer), kernel тимчасово **вимикає PAN** або використовує спеціальні інструкції для обходу.
- Після завершення доступу до user data треба знову увімкнути PAN.
- PXN забезпечується через page tables: user pages мають PXN = 1 (щоб kernel не міг їх виконувати), kernel pages не мають PXN (щоб kernel-код міг виконуватись).
- Kernel повинен гарантувати, що жоден кодовий шлях не призведе до виконання в user memory регіонах (що обійшло б PXN) — отже ланцюжки експлойтів, що спираються на «перехід у user-controlled shellcode», блокуються.
Через згаданий PAN bypass через execute-only сторінки, в реальній системі Apple може заборонити execute-only user pages або закрити цю прогалину патчами.
#### Attack surfaces, bypasses, and mitigations
- **PAN bypass через execute-only сторінки**: як обговорювалося, специфікація залишає прогалину: user сторінки з execute-only (без прав на читання) можуть не вважатися “доступними на EL0”, тож PAN не завадить kernel читати з таких сторінок в деяких реалізаціях. Це дає атакувальнику нестандартний шлях для передачі даних через execute-only секції.
- **Temporal window exploit**: якщо kernel вимикає PAN на вікно часу довше, ніж потрібно, гонка або шкідливий шлях може використати цей вікно для небажаного доступу до user memory.
- **Forgotten re-enable**: якщо шлях виконання забуває знову ввімкнути PAN, наступні операції ядра можуть некоректно отримувати доступ до user memory.
- **Misconfiguration of PXN**: якщо page tables не виставляють PXN на user pages або неправильно відображають user code pages, kernel може бути обманутий і виконати user-space код.
- **Speculation / side-channels**: аналогічно до спекулятивних обхідних шляхів, можуть існувати мікроархітектурні побічні ефекти, що приводять до транзиторних порушень перевірок PAN / PXN (хоча такі атаки сильно залежать від дизайну CPU).
- **Complex interactions**: у складніших функціональностях (наприклад JIT, shared memory, code regions для just-in-time), kernel може потребувати тонкого контролю, щоб дозволяти певні доступи або виконання в user-mapped регіонах; безпечне проектування таких механізмів під обмеженнями PAN/PXN нетривіальне.
#### Example
<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.
</details>
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs"> </span></div>
// 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
Якщо kernel **не** встановив PXN на тій user-сторінці, то перехід може виконатися успішно — що буде небезпечно.
Якщо kernel забуває повторно увімкнути PAN після доступу до пам’яті user, це відкриває вікно, в якому подальша логіка kernel може випадково читати/записувати довільну user-пам’ять.
Якщо user-указівник вказує на execute-only сторінку (user-сторінка з лише execute-дозволом, без read/write), під дією багу в специфікації PAN, `ldr W2, [X1]` може **не** спричинити fault навіть при увімкненому PAN, що дозволяє обхідний експлойт, залежно від реалізації.
</details>
<details>
<summary>Приклад</summary>
Вразливість у kernel намагається взяти вказівник на функцію, наданий user, і викликати його в контексті kernel (тобто `call user_buffer`). Під PAN/PXN така операція заборонена або призводить до fault.
</details>
---
### 11. **Top Byte Ignore (TBI) / Pointer Tagging**
**Introduced in ARMv8.5 / newer (or optional extension)**
TBI означає, що старший байт (найбільш значущий байт) 64-бітного вказівника ігнорується при трансляції адрес. Це дозволяє ОС або апаратурі вбудовувати **бит тега** у старший байт вказівника без впливу на фактичну адресу.
- TBI означає **Top Byte Ignore** (іноді називають *Address Tagging*). Це апаратна функція (доступна у багатьох реалізаціях ARMv8+), яка **ігнорує старші 8 біт** (біти 63:56) 64-бітного вказівника при виконанні **address translation / load/store / instruction fetch**.
- По суті, CPU трактує вказівник `0xTTxxxx_xxxx_xxxx` (де `TT` = старший байт) як `0x00xxxx_xxxx_xxxx` для цілей трансляції адрес, ігноруючи (маскуючи) старший байт. Старший байт може використовуватись програмним забезпеченням для збереження **metadata / tag bits**.
- Це дає програмі “безкоштовний” in-band простір для вбудовування одного байта тегу в кожен вказівник без зміни того, на яку ділянку пам’яті він посилається.
- Архітектура гарантує, що load-и, store-и та instruction fetch трактують вказівник із замаскованим старшим байтом (тобто тег знімається) перед фактичним доступом до пам’яті.
Таким чином, TBI розділяє **логічний вказівник** (pointer + tag) від **фізичної адреси**, яка використовується для операцій з пам’яттю.
#### Чому TBI: випадки використання та мотивація
- **Pointer tagging / metadata**: Ви можете зберігати додаткові метадані (наприклад, тип об’єкта, версію, межі, integrity tags) у цьому старшому байті. Коли потім використовуєте вказівник, тег ігнорується на апаратному рівні, тому не потрібно вручну знімати його для доступу до пам’яті.
- **Memory tagging / MTE (Memory Tagging Extension)**: TBI є базовим апаратним механізмом, на якому будується MTE. В ARMv8.5, **Memory Tagging Extension** використовує біти 59:56 вказівника як **логічний тег** і порівнює його з **allocation tag**, збереженим в пам’яті.
- **Підвищена безпека та цілісність**: Поєднавши TBI з pointer authentication (PAC) або runtime-перевірками, можна контролювати не лише значення вказівника, а й тег. Атакуючий, який перезаписує вказівник без правильного тегу, отримає невідповідність тегів.
- **Сумісність**: Оскільки TBI є опціональним і біти тегу ігноруються апаратурою, існуючий нетегований код продовжує працювати нормально. Бити тегу ефективно стають “неважливими” для застарілого коду.
#### Приклад
<details>
<summary>Приклад</summary>
У вказівнику на функцію був вбудований тег у старшому байті (скажімо `0xAA`). Експлойт перезаписує молодші біти вказівника, але ігнорує тег, тому коли kernel перевіряє або санітизує, вказівник завершує перевірку з помилкою або відхиляється.
</details>
---
### 12. **Page Protection Layer (PPL)**
**Introduced in late iOS / modern hardware (iOS ~17 / Apple silicon / high-end models)** (деякі звіти показують PPL у macOS / Apple silicon, але Apple переносить аналогічні захисти й на iOS)
- PPL спроектовано як **внутрішню межу захисту kernel**: навіть якщо kernel (EL1) скомпрометовано і має можливості читання/запису, **воно не повинно мати свободу вільно модифікувати** певні **чутливі сторінки** (особливо page tables, code-signing metadata, kernel code pages, entitlements, trust caches тощо).
- Це фактично створює **“kernel всередині kernel”** — менший довірений компонент (PPL) з **підвищеними привілеями**, який лише він може змінювати захищені сторінки. Інший kernel-код мусить викликати PPL-рутину для внесення змін.
- Це зменшує поверхню атаки для kernel-експлойтів: навіть маючи повний довільний R/W/execute у kernel-режимі, експлойт повинен ще й потрапити в домен PPL (або обійти PPL), щоб змінити критичні структури.
- На новіших Apple silicon (A15+ / M2+) Apple переходить до **SPTM (Secure Page Table Monitor)**, який у багатьох випадках замінює PPL для захисту page-table на цих платформах.
Ось як, як вважають на основі публічного аналізу, працює PPL:
#### Використання APRR / permission routing (APRR = Access Permission ReRouting)
- Apple hardware використовує механізм під назвою **APRR (Access Permission ReRouting)**, який дозволяє page table entries (PTE) містити невеликі індекси замість повних бітів дозволів. Ці індекси відображаються через APRR-регістр у фактичні дозволи. Це дозволяє динамічно переназначати дозволи для доменів.
- PPL використовує APRR для сегрегації привілеїв у контексті kernel: лише PPL-домен має право оновлювати відображення між індексами та ефективними дозволами. Тобто, коли не-PPL kernel-код записує PTE або намагається змінити біти дозволів, APRR-логіка відмовляє (або накладає read-only мапінг).
- PPL-код сам по собі виконується в обмеженій області (наприклад `__PPLTEXT`), яка зазвичай не виконується або не записується, поки вхідні шлюзи тимчасово не дозволять це. Kernel викликає PPL entry points (“PPL routines”) для виконання чутливих операцій.
#### Вхід / Вихід (Gate / Entry & Exit)
- Коли kernel потрібно змінити захищену сторінку (наприклад змінити дозволи kernel code page або модифікувати page tables), воно викликає **PPL wrapper** рутину, яка виконує валідацію та переходить у домен PPL. За межами цього домену захищені сторінки фактично є read-only або немодифікованими основним kernel.
- Під час входу в PPL, APRR-відображення коригуються так, щоб memory pages у PPL-регіоні були встановлені як **executable & writable** всередині PPL. Після виходу вони повертаються до read-only / non-writable. Це гарантує, що лише перевірені PPL-рутину можуть записувати в захищені сторінки.
- За межами PPL, спроби kernel-коду записати в ті захищені сторінки призведуть до fault (permission denied), оскільки APRR-відображення для того домену не дозволяє запис.
#### Категорії захищених сторінок
Сторінки, які PPL зазвичай захищає, включають:
- Структури page table (translation table entries, mapping metadata)
- Kernel code pages, особливо ті, що містять критичну логіку
- Code-sign metadata (trust caches, signature blobs)
- Entitlement tables, таблиці примусового підпису
- Інші високоцінні kernel-структури, де патч дозволив би обійти перевірки підписів або маніпуляції з обліковими даними
Ідея в тому, що навіть якщо пам’ять kernel повністю контролюється, нападник не може просто запатчити або перезаписати ці сторінки, якщо тільки він також не скомпрометував PPL-рутини або не обійшов PPL.
#### Відомі обходи та вразливості
1. **Project Zero’s PPL bypass (stale TLB trick)**
- Публічний розбір від Project Zero описує обхід, що включає **stale TLB entries**.
- Ідея:
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.
- Цей експлойт вимагав тонкого контролю за фізичним мапінгом і поведінкою TLB. Він демонструє, що межа безпеки, яка базується на коректності TLB/мапінгу, повинна бути надзвичайно уважною щодо invalidation-ів TLB та цілісності мапінгів.
- Project Zero зазначили, що обходи на кшталт цього є тонкими та рідкісними, але можливими в комплексних системах. Все ж, вони вважають PPL солідною мірою пом’якшення.
2. **Інші потенційні ризики та обмеження**
- Якщо kernel-експлойт може безпосередньо увійти в PPL-рутину (через виклики PPL wrapper-ів), він може обійти обмеження. Тому критично важлива валідація аргументів.
- Баги всередині PPL-коду (наприклад, арифметичний overflow, перевірки меж) можуть дозволити OOB-модифікації всередині PPL. Project Zero помітили, що такий баг у `pmap_remove_options_internal()` був використаний у їхньому обході.
- Межа PPL невід’ємно прив’язана до апаратного забезпечення (APRR, memory controller), тому вона тільки така сильна, як реалізація апаратного забезпечення.
#### Приклад
<details>
<summary>Code Example</summary>
Ось спрощена псевдологіка / pseudocode, що показує, як kernel може викликати PPL для модифікації захищених сторінок:
</details>
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">c</span></div>
```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
The kernel can do many normal operations, but only through ppl_call_*
routines can it change protected mappings or patch code.
Example
A kernel exploit tries to overwrite the entitlement table, or disable code-sign enforcement by modifying a kernel signature blob. Because that page is PPL-protected, the write is blocked unless going through the PPL interface. So even with kernel code execution, you cannot bypass code-sign constraints or modify credential data arbitrarily. On iOS 17+ certain devices use SPTM to further isolate PPL-managed pages.PPL → SPTM / Replacements / Future
- On Apple’s modern SoCs (A15 or later, M2 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.”
- The SPTM architecture likely shifts more policy enforcement into a higher-privileged monitor outside kernel control, further reducing the trust boundary.
MTE | EMTE | MIE
Here’s a higher-level description of how EMTE operates under Apple’s MIE setup:
- Tag assignment
- When memory is allocated (e.g. in kernel or user space via secure allocators), a secret tag is assigned to that block.
- The pointer returned to the user or kernel includes that tag in its high bits (using TBI / top byte ignore mechanisms).
- Tag checking on access
- Whenever a load or store is executed using a pointer, the hardware checks that the pointer’s tag matches the memory block’s tag (allocation tag). If mismatch, it faults immediately (since synchronous).
- Because it's synchronous, there is no “delayed detection” window.
- Retagging on free / reuse
- When memory is freed, the allocator changes the block’s tag (so older pointers with old tags no longer match).
- A use-after-free pointer would therefore have a stale tag and mismatch when accessed.
- Neighbor-tag differentiation to catch overflows
- Adjacent allocations are given distinct tags. If a buffer overflow spills into neighbor’s memory, tag mismatch causes a fault.
- This is especially powerful in catching small overflows that cross boundary.
- Tag confidentiality enforcement
- Apple must prevent tag values being leaked (because if attacker learns the tag, they could craft pointers with correct tags).
- They include protections (microarchitectural / speculative controls) to avoid side-channel leakage of tag bits.
- Kernel and user-space integration
- Apple uses EMTE not just in user-space but also in kernel / OS-critical components (to guard kernel against memory corruption).
- The hardware/OS ensures tag rules apply even when kernel is executing on behalf of 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>
#### Обмеження та виклики
- **Intrablock overflows**: Якщо переповнення залишається в межах тієї самої алокації (не переходить межу) і tag лишається тим самим, tag mismatch це не виявить.
- **Tag width limitation**: Доступно лише кілька бітів (наприклад, 4 біти, або невеликий домен) для tag — обмежений простір імен.
- **Side-channel leaks**: Якщо біти tag можуть бути leaked (via cache / speculative execution), атакуючий може дізнатися валідні теги і обійти захист. Apple’s tag confidentiality enforcement має на меті пом'якшити це.
- **Performance overhead**: Перевірки tag при кожному load/store додають витрати; Apple має оптимізувати hardware, щоб зменшити overhead.
- **Compatibility & fallback**: На старішому hardware або в частинах, що не підтримують EMTE, має існувати fallback. Apple стверджує, що MIE увімкнено лише на пристроях з підтримкою.
- **Complex allocator logic**: Allocator має керувати tags, retagging, вирівнюванням меж і уникати mis-tag collisions. Баги в логіці allocators можуть вводити вразливості.
- **Mixed memory / hybrid areas**: Деяка пам'ять може залишатися untagged (legacy), що ускладнює інтероперабельність.
- **Speculative / transient attacks**: Як і з багатьма мікроархітектурними захистами, speculative execution або micro-op fusions можуть тимчасово обходити перевірки або leak tag bits.
- **Limited to supported regions**: Apple може застосовувати EMTE лише в вибраних високоризикових зонах (kernel, security-critical subsystems), а не повсюдно.
---
## Ключові покращення / відмінності порівняно зі стандартним MTE
Here are the improvements and changes Apple emphasizes:
| Feature | Original MTE | EMTE (Apple’s enhanced) / MIE |
|---|---|---|
| **Check mode** | Підтримує synchronous та asynchronous режими. У async tag mismatches повідомляються пізніше (delayed) | Apple наполягає на **synchronous mode** за замовчуванням — tag mismatches фіксуються негайно, без вікон затримки/гонок. |
| **Coverage of non-tagged memory** | Доступи до non-tagged memory (e.g. globals) можуть обходити перевірки в деяких реалізаціях | EMTE вимагає, щоб доступи з tagged region до non-tagged memory також валідували знання тегу, ускладнюючи обхід через змішування алокацій. |
| **Tag confidentiality / secrecy** | Tags might be observable or leaked via side channels | Apple adds **Tag Confidentiality Enforcement**, яке намагається запобігти leakage of tag values (via speculative side-channels etc.). |
| **Allocator integration & retagging** | MTE leaves much of allocator logic to software | Apple’s secure typed allocators (kalloc_type, xzone malloc, etc.) інтегруються з EMTE: коли пам'ять виділяється або звільняється, tags керуються з тонкою гранулярністю. |
| **Always-on by default** | In many platforms, MTE is optional or off by default | Apple enables EMTE / MIE by default on supported hardware (e.g. iPhone 17 / A19) for kernel and many user processes. |
Оскільки Apple контролює і hardware, і software stack, вона може суворо впроваджувати EMTE, уникати проблем з продуктивністю та закривати side-channel дірки.
---
## Як EMTE працює на практиці (Apple / MIE)
Нижче — опис високого рівня того, як EMTE працює в налаштуванні Apple / MIE:
1. **Tag assignment**
- Коли пам'ять виділяється (наприклад, в kernel або user space через secure allocators), цьому блоку присвоюється **secret tag**.
- Pointer, що повертається користувачу або kernel, включає цей tag у старші біти (using TBI / top byte ignore mechanisms).
2. **Tag checking on access**
- Коли виконується load або store з використанням pointer, hardware перевіряє, що tag указівника відповідає tag блоку пам'яті (allocation tag). Якщо mismatch, виникає fault негайно (оскільки synchronous).
- Оскільки це synchronous, немає вікна «delayed detection».
3. **Retagging on free / reuse**
- Коли пам'ять звільняється, allocator змінює tag блоку (тому старі pointer'и зі старими тегами більше не співпадають).
- Use-after-free pointer отже матиме stale tag і призведе до mismatch при доступі.
4. **Neighbor-tag differentiation to catch overflows**
- Суміжним алокаціям призначаються різні теги. Якщо buffer overflow розливається в пам'ять сусіда, tag mismatch викликає fault.
- Це особливо ефективно для виявлення невеликих перетинних overflow, які переходять межу.
5. **Tag confidentiality enforcement**
- Apple має запобігти тому, щоб tag values були leaked (бо якщо атакуючий дізнається tag, він зможе створити pointers з правильними тегами).
- Вони додають захисти (microarchitectural / speculative controls), щоб уникнути side-channel leakage of tag bits.
6. **Kernel and user-space integration**
- Apple використовує EMTE не лише в user-space, а й в kernel / OS-critical components (щоб захистити kernel від memory corruption).
- Hardware/OS гарантує застосування правил tag навіть коли kernel виконується від імені user space.
Оскільки EMTE вбудовано в MIE, Apple використовує EMTE у synchronous режимі на ключових attack surfaces, а не як опціональний або debugging режим.
---
## Exception handling in XNU
Коли виникає **exception** (наприклад, `EXC_BAD_ACCESS`, `EXC_BAD_INSTRUCTION`, `EXC_CRASH`, `EXC_ARM_PAC`, тощо), **Mach layer** ядра XNU відповідає за перехоплення його до того, як воно стане UNIX-стилем **signal** (як-от `SIGSEGV`, `SIGBUS`, `SIGILL`, ...).
Цей процес включає кілька шарів propagation і обробки exception перед тим, як дійти до user space або бути перетвореним у BSD signal.
### Потік обробки виключень (High-Level)
1. **CPU triggers a synchronous exception** (наприклад, invalid pointer dereference, PAC failure, illegal instruction тощо).
2. **Low-level trap handler** запускається (`trap.c`, `exception.c` у джерелі XNU).
3. Trap handler викликає **`exception_triage()`**, ядро обробки Mach exception.
4. `exception_triage()` вирішує, куди маршрутизувати exception:
- Спочатку на **thread's exception port**.
- Потім на **task's exception port**.
- Потім на **host's exception port** (часто `launchd` або `ReportCrash`).
Якщо жоден з цих портів не обробляє exception, kernel може:
- **Convert it into a BSD signal** (для user-space процесів).
- **Panic** (для kernel-space exception).
### Основна функція: `exception_triage()`
Функція `exception_triage()` маршрутизує Mach exceptions по ланцюжку можливих обробників, поки якийсь не обробить їх або доки вони не стануть фатальними. Визначена в `osfmk/kern/exception.c`.
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">c</span></div>
```c
void exception_triage(exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t codeCnt);
Типовий порядок викликів:
exception_triage() └── exception_deliver() ├── exception_deliver_thread() ├── exception_deliver_task() └── exception_deliver_host()
Якщо всі вони не спрацьовують → обробляються bsd_exception()
→ перетворюються на сигнал типу SIGSEGV
.
Порти виключень
Кожен обʼєкт Mach (thread, task, host) може реєструвати порти виключень, куди надсилаються повідомлення про виключення.
Їх визначає API:
task_set_exception_ports()
thread_set_exception_ports()
host_set_exception_ports()
Кожен exception port має:
- Маску (які винятки він хоче отримувати)
- Ім'я порту (Mach port для отримання повідомлень)
- Поведінку (як kernel відправляє повідомлення)
- Флейвор (який thread state включити)
Debuggers and Exception Handling
Дебагер (наприклад, LLDB) встановлює exception port на цільовому task або thread, зазвичай використовуючи task_set_exception_ports()
.
Коли відбувається виняток:
- Mach message відправляється в процес дебагера.
- Дебагер може вирішити обробити (resume, змінити регістри, пропустити інструкцію) або не обробляти виняток.
- Якщо дебагер не обробляє його, виняток поширюється на наступний рівень (task → host).
Flow of EXC_BAD_ACCESS
-
Thread дереференсує некоректний вказівник → CPU піднімає Data Abort.
-
Kernel trap handler викликає
exception_triage(EXC_BAD_ACCESS, ...)
. -
Повідомлення відправляється на:
-
Thread port → (debugger може перехопити breakpoint).
-
Якщо debugger ігнорує → Task port → (process-level handler).
-
Якщо ігнорують → Host port (зазвичай ReportCrash).
- Якщо ніхто не обробляє →
bsd_exception()
перетворює вSIGSEGV
.
PAC Exceptions
Коли Pointer Authentication (PAC) не проходить (невідповідність підпису), піднімається спеціальний Mach exception:
EXC_ARM_PAC
(type)- Codes можуть містити деталі (наприклад, тип ключа, тип вказівника).
Якщо бінар має прапор TFRO_PAC_EXC_FATAL
, kernel трактує збої PAC як фатальні, оминаючи перехоплення дебагером. Це зроблено, щоб запобігти використанню дебагерів для обходу PAC перевірок і увімкнено для platform binaries.
Software Breakpoints
Software breakpoint (int3
на x86, brk
на ARM64) реалізується шляхом навмисного виклику fault.
Дебагер ловить це через exception port:
- Змінює instruction pointer або пам'ять.
- Відновлює оригінальну інструкцію.
- Продовжує виконання.
Цей же механізм дозволяє "піймати" PAC exception — якщо тільки TFRO_PAC_EXC_FATAL
не встановлений, у такому випадку він ніколи не доходить до дебагера.
Conversion to BSD Signals
Якщо жоден хендлер не приймає виняток:
-
Kernel викликає
task_exception_notify() → bsd_exception()
. -
Це відображає Mach exceptions у сигнали:
Назва зони | Розмір елемента | Приклад використання |
---|---|---|
default.kalloc.16 | 16 bytes | Дуже малі kernel structs, pointers. |
default.kalloc.32 | 32 bytes | Малі структури, заголовки об'єктів. |
default.kalloc.64 | 64 bytes | IPC messages, крихітні kernel buffers. |
default.kalloc.128 | 128 bytes | Середні об'єкти, наприклад частини OSObject . |
… | … | … |
default.kalloc.1280 | 1280 bytes | Великі структури, IOSurface/graphics metadata. |
(Відповідність Mach Exception → Signal)
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 (on non-fatal) |
### Key Files in XNU Source
-
osfmk/kern/exception.c
→ Ядроexception_triage()
,exception_deliver_*()
. -
bsd/kern/kern_sig.c
→ Логіка доставлення сигналів. -
osfmk/arm64/trap.c
→ Низькорівневі trap handlers. -
osfmk/mach/exc.h
→ Exception codes та структури. -
osfmk/kern/task.c
→ Налаштування task exception port.
Old Kernel Heap (Pre-iOS 15 / Pre-A12 era)
Ядро використовувало zone allocator (kalloc
), поділений на фіксовані "зони".
Кожна зона зберігала лише алокації одного розміру.
Зі скріншоту:
Назва зони | Розмір елемента | Приклад використання |
---|---|---|
default.kalloc.16 | 16 bytes | Дуже малі kernel structs, pointers. |
default.kalloc.32 | 32 bytes | Малі структури, заголовки об'єктів. |
default.kalloc.64 | 64 bytes | IPC messages, крихітні kernel buffers. |
default.kalloc.128 | 128 bytes | Середні об'єкти, наприклад частини OSObject . |
… | … | … |
default.kalloc.1280 | 1280 bytes | Великі структури, IOSurface/graphics metadata. |
Як це працювало:
- Кожен запит на алокацію округлювався вгору до найближчого розміру зони.
(Напр., запит на 50 байт потрапляв у зону
kalloc.64
). - Пам'ять у кожній зоні зберігалася у freelist — чанки, звільнені kernel-ом, поверталися в ту ж зону.
- Якщо ви переповнювали буфер на 64 байти, ви перезаписували наступний об'єкт у тій самій зоні.
Саме тому heap spraying / feng shui був настільки ефективним: ви могли передбачити сусідів об'єктів, заповнюючи алокації одного розміру.
The freelist
Всередині кожної kalloc зони звільнені об'єкти не поверталися прямо в систему — вони йшли у freelist, зв'язаний список доступних чанків.
-
Коли чанк звільнявся, kernel записував в початок того чанку вказівник → адресу наступного вільного чанку в тій же зоні.
-
Зона тримала HEAD вказівник на перший вільний чанк.
-
Алокація завжди використовувала поточний HEAD:
- Pop HEAD (повернути цю пам'ять виклику).
- Оновити HEAD = HEAD->next (збережено в заголовку звільненого чанку).
-
Звільнення штовхало чанки назад:
-
freed_chunk->next = HEAD
-
HEAD = freed_chunk
Отже, freelist був просто зв'язаним списком, побудованим всередині самої звільненої пам'яті.
Нормальний стан:
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)
Експлуатація freelist
Оскільки перші 8 байтів free chunk = freelist pointer, зловмисник може його пошкодити:
-
Heap overflow у сусідній freed chunk → перезаписати його “next” pointer.
-
Use-after-free запис у freed object → перезаписати його “next” pointer.
Потім, при наступній allocation такого розміру:
- Allocator витягує corrupted chunk.
- Слідує за attacker-supplied “next” pointer.
- Повертає pointer на довільну пам'ять, що дозволяє fake object primitives або targeted overwrite.
Візуальний приклад 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.
Цей дизайн freelist зробив експлуатацію надзвичайно ефективною до впровадження hardening: передбачувані сусіди від heap sprays, raw pointer freelist links та відсутність розділення типів дозволяли атакам ескалувати UAF/overflow в можливість довільного контролю пам’яті ядра.
Heap Grooming / Feng Shui
Мета heap grooming — сформувати розкладку heap так, щоб коли атакуючий викликає overflow або use-after-free, цільовий (victim) об’єкт опинився безпосередньо поруч з атаковано-контрольованим об’єктом.
Так, при корупції пам’яті атакуючий може надійно перезаписати пам’ять victim об’єкта керованими даними.
Кроки:
- Spray allocations (fill the holes)
- З часом heap ядра фрагментується: в деяких зонах з’являються «діри», де старі об’єкти були freed.
- Атакуючий спочатку робить велику кількість dummy allocations, щоб заповнити ці прогалини, роблячи heap «щільним» і передбачуваним.
- Force new pages
- Після заповнення дірок наступні алокації мають прийти з нових сторінок, доданих до зони.
- Нові сторінки означають, що об’єкти будуть згруповані разом, а не розкидані по старій фрагментованій пам’яті.
- Це дає атакуючому значно кращий контроль над сусідами.
- Place attacker objects
- Тепер атакуючий знову робить spray, створюючи багато атаковано-контрольованих об’єктів на тих нових сторінках.
- Ці об’єкти мають передбачуваний розмір і розміщення (оскільки вони належать до однієї зони).
- Free a controlled object (make a gap)
- Атакуючий умисно звільняє один зі своїх об’єктів.
- Це створює «діру» в heap, яку allocator пізніше використає для наступної алокації того самого розміру.
- Victim object lands in the hole
- Атакуючий викликає kernel для алокації victim об’єкта (того, який він хоче пошкодити).
- Оскільки дірка — перший доступний слот у freelist, victim поміщається саме туди, де атакуючий звільнив свій об’єкт.
- Overflow / UAF into victim
- Тепер атакуючий має контрольовані об’єкти навколо victim.
- Переповнивши один зі своїх об’єктів (або використавши freed об’єкт повторно), він може надійно перезаписати поля victim з вибраними значеннями.
Чому це працює:
- Zone allocator predictability: алокації одного й того ж розміру завжди приходять з тієї самої зони.
- Freelist behavior: нові алокації повторно використовують найсвіжіше freed місце першим.
- Heap sprays: атакуючий заповнює пам’ять передбачуваним контентом і контролює layout.
- Підсумок: атакуючий контролює, куди потрапить victim і які дані стоятимуть поруч із ним.
Сучасна куча ядра (iOS 15+/A12+ SoCs)
Apple підсилила allocator і зробила heap grooming набагато складнішим:
1. From Classic kalloc to kalloc_type
- Before: існувала єдина зона
kalloc.<size>
для кожного класу розміру (16, 32, 64, … 1280 і т.д.). Будь-який об’єкт цього розміру поміщався туди → атакуючі могли розміщувати свої об’єкти поруч з привілейованими об’єктами ядра. - Now:
- Kernel objects алокуються з typed zones (
kalloc_type
). - Кожен тип об’єкта (наприклад,
ipc_port_t
,task_t
,OSString
,OSData
) має власну виділену зону, навіть якщо вони одного розміру. - Відображення між типом об’єкта ↔ зоною генерується системою kalloc_type під час компіляції.
Атакуючий більше не може гарантувати, що controlled data (OSData
) опиниться поруч з чутливими kernel objects (task_t
) того ж розміру.
2. Slabs and Per-CPU Caches
- Heap розділено на slabs (сторінки пам’яті, порізані на фіксовані чанки для цієї зони).
- Кожна зона має per-CPU cache, щоб зменшити contention.
- Шлях алокації:
- Спробувати per-CPU cache.
- Якщо порожній, взяти з global freelist.
- Якщо freelist порожній, алокувати новий slab (одну або більше сторінок).
- Перевага: ця децентралізація робить heap sprays менш детермінованими, оскільки алокації можуть задовольнятися з кешів різних CPU.
3. Randomization inside zones
- В межах зони freed елементи не повертаються в простому FIFO/LIFO порядку.
- Сучасний XNU використовує encoded freelist pointers (подібно до safe-linking в Linux, уведено приблизно з iOS 14).
- Кожен freelist pointer XOR-шифрується з per-zone secret cookie.
- Це заважає атакуючому створити підроблений freelist pointer, якщо він отримає write primitive.
- Деякі алокації рандомізуються в їхньому розміщенні всередині slab, тому spraying не гарантує суміжності.
4. Guarded Allocations
- Деякі критичні kernel об’єкти (наприклад, credentials, task structures) алокуються в guarded zones.
- Ці зони вставляють guard pages (немапована пам’ять) між slabs або використовують redzones навколо об’єктів.
- Будь-який overflow у guard page викликає fault → миттєвий panic замість тихої корупції.
5. Page Protection Layer (PPL) and SPTM
- Навіть якщо ви контролюєте freed об’єкт, ви не можете змінити всю пам’ять ядра:
- PPL (Page Protection Layer) забезпечує, що певні регіони (наприклад, code signing data, entitlements) є read-only навіть для самого ядра.
- На A15/M2+ пристроях роль PPL замінена/посилена SPTM (Secure Page Table Monitor) + TXM (Trusted Execution Monitor).
- Ці апаратні шари означають, що атакуючі не можуть піднятись від однієї корупції heap до довільного патчингу критичних структур безпеки.
- (Додано / Посилено): також в ядрі використовується PAC (Pointer Authentication Codes) для захисту вказівників (особливо function pointers, vtables), тож підробка або корупція таких вказівників стає складнішою.
- (Додано / Посилено): зони можуть застосовувати zone_require / zone enforcement, тобто об’єкт після free може бути повернений лише через коректну typed zone; некоректні cross-zone frees можуть викликати panic або бути відхилені. (Apple натякає на це у своїх матеріалах про memory safety)
6. Large Allocations
- Не всі алокації проходять через
kalloc_type
. - Дуже великі запити (понад ~16 KB) обходять typed zones і обслуговуються безпосередньо з kernel VM (kmem) через page allocations.
- Вони менш передбачувані, але й менш експлуатовані, оскільки не ділять slabs з іншими об’єктами.
7. Allocation Patterns Attackers Target
Навіть з цими захистами, атакуючі все ще шукають:
- Reference count objects: якщо можна маніпулювати retain/release лічильниками, це може призвести до use-after-free.
- Objects with function pointers (vtables): корупція таких об’єктів все ще дає контроль над виконанням.
- Shared memory objects (IOSurface, Mach ports): вони залишаються цілями, бо мостять user ↔ kernel.
Але — на відміну від раніше — ви не можете просто spray’ити OSData
і очікувати, що він сусідитиме з task_t
. Потрібні type-specific bugs або info leaks для успіху.
Example: Allocation Flow in Modern Heap
Припустимо, userspace викликає IOKit для алокації об’єкта OSData
:
- Type lookup →
OSData
відображається на зонуkalloc_type_osdata
(size 64 bytes). - Перевірити per-CPU cache на наявність вільних елементів.
- Якщо знайдено → повернути один.
- Якщо порожній → звернутися до global freelist.
- Якщо freelist порожній → алокувати новий slab (сторінка 4KB → 64 чанки по 64 байти).
- Повернути chunk виклику.
Захист freelist pointer:
- Кожен freed chunk зберігає адресу наступного вільного chunk, але закодовану з секретним ключем.
- Перезапис цього поля даними атакуючого не спрацює, якщо ви не знаєте ключа.
Порівняльна таблиця
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 |
Сучасна userland куча (iOS, macOS — type-aware / xzone malloc)
В останніх версіях Apple OS (особливо iOS 17+) Apple представила більш безпечний userland allocator, xzone malloc (XZM). Це user-space аналог kernel-ного kalloc_type
, що застосовує type awareness, ізоляцію метаданих і механізми memory tagging.
Цілі та принципи дизайну
- Type segregation / type awareness: групувати алокації за типом або призначенням (pointer vs data), щоб запобігти type confusion і cross-type reuse.
- Metadata isolation: відокремити heap metadata (наприклад, free lists, size/state біти) від payload об’єктів, щоб out-of-bounds записи рідше псували метадані.
- Guard pages / redzones: вставляти немаповані сторінки або padding навколо алокацій для виявлення overflow.
- Memory tagging (EMTE / MIE): працювати разом з апаратним tagging для виявлення use-after-free, out-of-bounds і некоректних доступів.
- Scalable performance: зберігати низькі накладні витрати, уникати надмірної фрагментації і підтримувати багато алокацій з низькою затримкою.
Архітектура та компоненти
Нижче — основні елементи alloc-ра xzone:
Segment Groups & Zones
- Segment groups розділяють адресний простір за категоріями використання: наприклад
data
,pointer_xzones
,data_large
,pointer_large
. - Кожна група містить segments (VM-ділянки), що хостять алокації для цієї категорії.
- До кожного сегмента приєднаний metadata slab (окрема VM-ділянка), яка зберігає metadata (наприклад, free/used біти, size classes) для цього сегмента. Ця out-of-line (OOL) metadata гарантує, що метадані не змішуються з payload об’єктів, зменшуючи ризик корупції при overflow.
- Сегменти розбиваються на chunks (сегменти), які в свою чергу діляться на blocks (осередки для алокацій). Chunk прив’язаний до конкретного size class і segment group (тобто всі блоки в chunk мають той самий розмір і категорію).
- Для малих/середніх алокацій використовуються фіксовані chunks; для великих/дуже великих може відбуватися окрема mapping.
Chunks & Blocks
- Chunk — це регіон (часто кілька сторінок), присвячений алокаціям одного size class всередині групи.
- Всередині chunk blocks — слоти для алокацій. Freed blocks відстежуються через metadata slab — наприклад, через bitmap або free lists, збережені out-of-line.
- Між chunks (або всередині) можуть бути вставлені guard slices / guard pages (напр., немаповані ділянки) для виявлення out-of-bounds записів.
Type / Type ID
- Кожне місце алокації (або виклик malloc, calloc тощо) асоціюється з type identifier (типу
malloc_type_id_t
), який кодує, який саме об’єкт алокується. Цей type ID передається allocator-у, який використовує його для вибору відповідного сегменту/зони. - Завдяки цьому, навіть якщо дві алокації одного розміру, вони можуть потрапити у зовсім різні зони, якщо їхні типи відрізняються.
- У ранніх версіях iOS 17 не всі API (наприклад, CFAllocator) були повністю type-aware; Apple вирішила деякі з цих слабких місць в iOS 18.
Workflow алокації та звільнення
Ось високорівневий flow алокації й деалокації в xzone:
- Викликається malloc / calloc / realloc / typed alloc з розміром і type ID.
- Allocator використовує type ID для вибору правильної segment group / zone.
- В межах цієї зони/сегмента шукають chunk, що має вільні блоки потрібного розміру.
- Можуть перевіряти local caches / per-thread pools або free block lists з metadata.
- Якщо вільного блоку немає, можуть алокувати новий chunk у цій зоні.
- Оновлюється metadata slab (звільнений біт очищається, ведеться bookkeeping).
- Якщо працює memory tagging (EMTE), повернений блок отримує tag, і metadata оновлюється, відмічаючи його як «live».
- Коли викликається
free()
:
- Блок помічають як freed у metadata (через OOL slab).
- Блок може бути поміщений у free list або pooled для повторного використання.
- За бажанням, вміст блоку може бути очищений або отруєний (poisoned), щоб зменшити витоки даних або експлуатацію UAF.
- Апаратний tag, що асоціюється з блоком, може бути інвалідований або перевідмічений.
- Якщо увесь chunk стає вільним (усі блоки freed), allocator може reclaim цей chunk (анмапити його або повернути ОС) під час тиску пам’яті.
Функції безпеки та hardening
Це захисти, вбудовані у сучасний userland xzone:
Feature | Purpose | Notes |
---|---|---|
Metadata decoupling | Prevent overflow from corrupting metadata | Metadata lives in separate VM region (metadata slab) |
Guard pages / unmapped slices | Catch out-of-bounds writes | Helps detect buffer overflows rather than silently corrupting adjacent blocks |
Type-based segregation | Prevent cross-type reuse & type confusion | Even same-size allocations from different types go to different zones |
Memory Tagging (EMTE / MIE) | Detect invalid access, stale references, OOB, UAF | xzone works in concert with hardware EMTE in synchronous mode (“Memory Integrity Enforcement”) |
Delayed reuse / poisoning / zap | Reduce chance of use-after-free exploitation | Freed blocks may be poisoned, zeroed, or quarantined before reuse |
Chunk reclamation / dynamic unmapping | Reduce memory waste and fragmentation | Entire chunks may be unmapped when unused |
Randomization / placement variation | Prevent deterministic adjacency | Blocks in a chunk and chunk selection may have randomized aspects |
Segregation of “data-only” allocations | Separate allocations that don’t store pointers | Reduces attacker control over metadata or control fields |
Взаємодія з Memory Integrity Enforcement (MIE / EMTE)
- Apple’s MIE (Memory Integrity Enforcement) — це апаратно-озгаджувальна + ОС-рамка, яка робить Enhanced Memory Tagging Extension (EMTE) завжди увімкненим, у синхронному режимі по основних атаках.
- xzone allocator є фундаментом MIE в user space: алокації через xzone отримують теги, і доступи перевіряються апаратурою.
- В MIE allocator, призначення тегів, управління metadata і забезпечення конфіденційності тегів інтегровані так, щоб memory errors (наприклад, stale reads, OOB, UAF) виявлялися негайно, а не використовувалися пізніше.
Якщо хочеш, я також можу згенерувати cheat-sheet або діаграму внутрішньої архітектури xzone для твоєї книжки. Хочеш, щоб я зробив це наступним?
::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
.ipsw
files. - Decompress until you get the bin format of the kernelcache of both
.ipsw
files. 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 BinDiff
and 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
.
iMessage/Media Parser Zero-Click Chains
Imessage Media Parser Zero Click Coreaudio Pac Bypass
tip
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.