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}}
|
{{#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)**:
|
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)**:
|
2. **L2 Page Table (Level 2)**:
|
||||||
* An entry here represents a smaller region of virtual memory, specifically **0x2000000 bytes** (32 MB).
|
* Запис тут представляє менший регіон віртуальної пам'яті, а саме **0x2000000 bytes** (32 MB).
|
||||||
* An L1 entry may point to an L2 table if it can't map the entire region itself.
|
* Запис L1 може вказувати на таблицю L2, якщо не може відобразити весь регіон самостійно.
|
||||||
3. **L3 Page Table (Level 3)**:
|
3. **L3 Page Table (Level 3)**:
|
||||||
* This is the finest level, where each entry maps a single **4 KB** memory page.
|
* Це найдрібніший рівень, де кожен запис відображає одну сторінку пам'яті розміром **4 KB**.
|
||||||
* An L2 entry may point to an L3 table if more granular control is needed.
|
* Запис L2 може вказувати на таблицю L3, якщо потрібен більш детальний контроль.
|
||||||
|
|
||||||
#### Відображення віртуальної пам'яті в фізичну
|
#### Mapping Virtual to Physical Memory
|
||||||
|
|
||||||
* **Direct Mapping (Block Mapping)**:
|
* **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**:
|
* **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**:
|
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**:
|
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**:
|
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**.
|
* Віртуальні адреси від **0x1000000000** до **0x1002000000** відображатимуться на фізичні адреси від **0x800004000** до **0x802004000**.
|
||||||
* This is a **block mapping** at the L2 level.
|
* Це є **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**.
|
1. Процес **виділяє** певну пам'ять як **читабельну і записувану**.
|
||||||
2. The **page tables** are updated to map this memory to a specific physical address that the process can access.
|
2. **Таблиці сторінок** оновлюються для відображення цієї пам'яті на конкретну фізичну адресу, до якої процес має доступ.
|
||||||
3. The process **deallocates** (frees) the memory.
|
3. Процес **звільняє** (deallocate) цю пам'ять.
|
||||||
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.
|
4. Однак через **баг** ядро **забуває видалити відображення** з таблиць сторінок, навіть якщо відповідна фізична пам'ять позначена як вільна.
|
||||||
5. The kernel can then **reallocate this "freed" physical memory** for other purposes, like **kernel data**.
|
5. Ядро може потім **перевиділити цю "звільнену" фізичну пам'ять** для інших цілей, наприклад для **даних ядра**.
|
||||||
6. Since the mapping wasn’t removed, the process can still **read and write** to this physical memory.
|
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
|
### 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.
|
1. Атакуючий **створює велику кількість об'єктів IOSurface** в пам'яті ядра.
|
||||||
2. Each IOSurface object contains a **magic value** in one of its fields, making it easy to identify.
|
2. Кожен об'єкт IOSurface містить **магічне значення** в одному зі своїх полів, що полегшує ідентифікацію.
|
||||||
3. They **scan the freed pages** to see if any of these IOSurface objects landed on a freed page.
|
3. Вони **сканують звільнені сторінки**, щоб перевірити, чи потрапив на якусь із них об'єкт IOSurface.
|
||||||
4. When they find an IOSurface object on a freed page, they can use it to **read and write kernel memory**.
|
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]
|
> [!TIP]
|
||||||
> Be aware that iOS 16+ (A12+) devices bring hardware mitigations (like PPL or SPTM) that make physical UAF techniques far less viable.
|
> Зверніть увагу, що пристрої iOS 16+ (A12+) мають апаратні запобіжники (наприклад, PPL або SPTM), які роблять техніки фізичного UAF значно менш життєздатними.
|
||||||
> 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.
|
> PPL застосовує суворі MMU-захисти до сторінок, пов'язаних з підписуванням коду, entitlements та чутливими даними ядра, тому навіть якщо сторінка буде перевикористана, записи з userland або скомпрометованого коду ядра до сторінок, захищених PPL, будуть заблоковані.
|
||||||
> 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.
|
> Secure Page Table Monitor (SPTM) розширює PPL, підвищуючи захист оновлень таблиць сторінок. Він забезпечує, що навіть привілейований код ядра не може непомітно перемапити звільнені сторінки або змінити відображення без проходження через захищені перевірки.
|
||||||
> 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.
|
> KTRR (Kernel Text Read-Only Region) фіксує секцію коду ядра як лише для читання після завантаження. Це запобігає будь-яким runtime-змінам коду ядра, закриваючи велику вразливість, на яку часто спираються експлойти фізичного UAF.
|
||||||
> 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.
|
> Більше того, `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").
|
1. **Spray IOSurface Objects**: Атакуючий створює багато об'єктів IOSurface зі спеціальним ідентифікатором ("magic value").
|
||||||
2. **Scan Freed Pages**: They check if any of the objects have been allocated on a freed page.
|
2. **Scan Freed Pages**: Вони перевіряють, чи який-небудь із об'єктів був виділений на звільненій сторінці.
|
||||||
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:
|
3. **Read/Write Kernel Memory**: Маніпулюючи полями об'єкта IOSurface, вони отримують можливість виконувати **довільні читання і записи** в пам'ять ядра. Це дозволяє їм:
|
||||||
* Use one field to **read any 32-bit value** in kernel memory.
|
* Використати одне поле, щоб **читати будь-яке 32-бітне значення** в пам'яті ядра.
|
||||||
* Use another field to **write 64-bit values**, achieving a stable **kernel read/write primitive**.
|
* Використати інше поле, щоб **записувати 64-бітні значення**, досягаючи стабільного **kernel read/write primitive**.
|
||||||
|
|
||||||
Згенеруйте об'єкти IOSurface з магічним значенням IOSURFACE\_MAGIC для подальшого пошуку:
|
Згенеруйте об'єкти IOSurface зі значенням-маркером IOSURFACE_MAGIC, щоб пізніше шукати:
|
||||||
```c
|
```c
|
||||||
void spray_iosurface(io_connect_t client, int nSurfaces, io_connect_t **clients, int *nClients) {
|
void spray_iosurface(io_connect_t client, int nSurfaces, io_connect_t **clients, int *nClients) {
|
||||||
if (*nClients >= 0x4000) return;
|
if (*nClients >= 0x4000) return;
|
||||||
@ -114,7 +114,7 @@ io_connect_t id = result.surface_id;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
Шукати об'єкти **`IOSurface`** в одній звільненій фізичній сторінці:
|
Пошук **`IOSurface`** об'єктів в одній вивільненій фізичній сторінці:
|
||||||
```c
|
```c
|
||||||
int iosurface_krw(io_connect_t client, uint64_t *puafPages, int nPages, uint64_t *self_task, uint64_t *puafPage) {
|
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);
|
io_connect_t *surfaceIDs = malloc(sizeof(io_connect_t) * 0x4000);
|
||||||
@ -148,25 +148,25 @@ free(surfaceIDs);
|
|||||||
return 0;
|
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 має два ключові поля:
|
Об'єкт IOSurface має два ключові поля:
|
||||||
|
|
||||||
1. **Use Count Pointer**: дозволяє **32-bit read**.
|
1. **Use Count Pointer**: Дозволяє **32-бітне читання**.
|
||||||
2. **Indexed Timestamp Pointer**: дозволяє **64-bit write**.
|
2. **Indexed Timestamp Pointer**: Дозволяє **64-бітовий запис**.
|
||||||
|
|
||||||
Перезаписуючи ці вказівники, ми перенаправляємо їх на довільні адреси в kernel memory, що дає можливість читання/запису.
|
Перезаписавши ці вказівники, ми перенаправляємо їх на довільні адреси в пам'яті ядра, що дає можливість читання та запису.
|
||||||
|
|
||||||
#### 32-Bit Kernel Read
|
#### 32-Bit Kernel Read
|
||||||
|
|
||||||
Щоб виконати читання:
|
Щоб виконати читання:
|
||||||
|
|
||||||
1. Перезапишіть **use count pointer**, щоб він вказував на цільову адресу мінус 0x14-byte offset.
|
1. Перезапишіть **use count pointer**, щоб він вказував на цільову адресу мінус 0x14 байт.
|
||||||
2. Використайте метод `get_use_count`, щоб прочитати значення за цією адресою.
|
2. Використайте метод `get_use_count` для читання значення за цією адресою.
|
||||||
```c
|
```c
|
||||||
uint32_t get_use_count(io_connect_t client, uint32_t surfaceID) {
|
uint32_t get_use_count(io_connect_t client, uint32_t surfaceID) {
|
||||||
uint64_t args[1] = {surfaceID};
|
uint64_t args[1] = {surfaceID};
|
||||||
@ -184,12 +184,12 @@ iosurface_set_use_count_pointer(info.object, orig);
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
#### 64-Bit Kernel Write
|
#### 64-Bit Kernel Запис
|
||||||
|
|
||||||
Щоб виконати запис:
|
Щоб виконати запис:
|
||||||
|
|
||||||
1. Перезапишіть **indexed timestamp pointer**, щоб він вказував на цільну адресу.
|
1. Перезаписати **indexed timestamp pointer** на цільову адресу.
|
||||||
2. Використайте метод `set_indexed_timestamp` для запису 64-бітного значення.
|
2. Використати метод `set_indexed_timestamp` для запису 64-бітного значення.
|
||||||
```c
|
```c
|
||||||
void set_indexed_timestamp(io_connect_t client, uint32_t surfaceID, uint64_t value) {
|
void set_indexed_timestamp(io_connect_t client, uint32_t surfaceID, uint64_t value) {
|
||||||
uint64_t args[3] = {surfaceID, 0, 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);
|
iosurface_set_indexed_timestamp_pointer(info.object, orig);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
#### Підсумок потоку експлойту
|
#### Exploit Flow Recap
|
||||||
|
|
||||||
1. **Trigger Physical Use-After-Free**: Вивільнені сторінки доступні для повторного використання.
|
1. **Trigger Physical Use-After-Free**: Вільні сторінки стають доступними для повторного використання.
|
||||||
2. **Spray IOSurface Objects**: Allocate many IOSurface objects with a unique "magic value" in kernel memory.
|
2. **Spray IOSurface Objects**: Виділяються численні об'єкти IOSurface з унікальним "magic value" в kernel memory.
|
||||||
3. **Identify Accessible IOSurface**: Знайдіть IOSurface на вивільненій сторінці, якою ви керуєте.
|
3. **Identify Accessible IOSurface**: Знайти IOSurface на звільненій сторінці, якою ви керуєте.
|
||||||
4. **Abuse Use-After-Free**: Змініть вказівники в об'єкті IOSurface, щоб отримати довільні **kernel read/write** через методи 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}}
|
{{#include ../../banners/hacktricks-training.md}}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user