mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/binary-exploitation/libc-heap/use-after-free/first-fit.
This commit is contained in:
parent
c45eeb4837
commit
86b22f5b6e
@ -4,18 +4,18 @@
|
||||
|
||||
## **First Fit**
|
||||
|
||||
Коли ви звільняєте пам'ять у програмі, використовуючи glibc, різні "контейнери" використовуються для управління шматками пам'яті. Ось спрощене пояснення двох поширених сценаріїв: несортовані контейнери та швидкі контейнери.
|
||||
Коли ви звільняєте пам'ять у програмі, використовуючи glibc, різні "контейнери" використовуються для управління шматками пам'яті. Ось спрощене пояснення двох поширених сценаріїв: незасортовані контейнери та швидкі контейнери.
|
||||
|
||||
### Несортовані Контейнери
|
||||
### Unsorted Bins
|
||||
|
||||
Коли ви звільняєте шматок пам'яті, який не є швидким шматком, він потрапляє до несортованого контейнера. Цей контейнер діє як список, де нові звільнені шматки додаються на початок (до "голови"). Коли ви запитуєте новий шматок пам'яті, аллокатор дивиться на несортований контейнер ззаду (до "хвоста"), щоб знайти шматок, який достатньо великий. Якщо шматок з несортованого контейнера більший, ніж вам потрібно, він розділяється, причому передня частина повертається, а залишкова частина залишається в контейнері.
|
||||
Коли ви звільняєте шматок пам'яті, який не є швидким шматком, він потрапляє до незасортованого контейнера. Цей контейнер діє як список, де нові звільнені шматки додаються на початок (до "голови"). Коли ви запитуєте новий шматок пам'яті, аллокатор дивиться на незасортований контейнер ззаду (до "хвоста"), щоб знайти шматок, який достатньо великий. Якщо шматок з незасортованого контейнера більший, ніж вам потрібно, він розділяється, при цьому передня частина повертається, а залишок залишається в контейнері.
|
||||
|
||||
Приклад:
|
||||
|
||||
- Ви виділяєте 300 байт (`a`), потім 250 байт (`b`), звільняєте `a` і знову запитуєте 250 байт (`c`).
|
||||
- Коли ви звільняєте `a`, він потрапляє до несортованого контейнера.
|
||||
- Якщо ви знову запитуєте 250 байт, аллокатор знаходить `a` на хвості і розділяє його, повертаючи частину, яка відповідає вашому запиту, а решту залишаючи в контейнері.
|
||||
- `c` буде вказувати на попереднє `a` і заповнене `a's`.
|
||||
- Ви виділяєте 300 байт (`a`), потім 250 байт (`b`), потім звільняєте `a` і знову запитуєте 250 байт (`c`).
|
||||
- Коли ви звільняєте `a`, він потрапляє до незасортованого контейнера.
|
||||
- Якщо ви знову запитуєте 250 байт, аллокатор знаходить `a` на хвості і розділяє його, повертаючи частину, яка відповідає вашому запиту, і залишаючи решту в контейнері.
|
||||
- `c` буде вказувати на попереднє `a` і буде заповнено вмістом `a`.
|
||||
```c
|
||||
char *a = malloc(300);
|
||||
char *b = malloc(250);
|
||||
@ -24,13 +24,9 @@ char *c = malloc(250);
|
||||
```
|
||||
### Fastbins
|
||||
|
||||
Fastbins використовуються для малих обсягів пам'яті. На відміну від несортованих бінів, fastbins додають нові шматки на початок, створюючи поведінку останній прийшов - перший вийшов (LIFO). Якщо ви запитуєте малий шматок пам'яті, аллокатор витягне з голови fastbin.
|
||||
Fastbins використовуються для малих обсягів пам'яті. На відміну від несортованих бінів, fastbins додають нові обсяги на початок, створюючи поведінку останній прийшов - перший вийшов (LIFO). Якщо ви запитуєте малий обсяг пам'яті, аллокатор витягне з голови fastbin.
|
||||
|
||||
Приклад:
|
||||
|
||||
- Ви виділяєте чотири шматки по 20 байт кожен (`a`, `b`, `c`, `d`).
|
||||
- Коли ви звільняєте їх у будь-якому порядку, звільнені шматки додаються до голови fastbin.
|
||||
- Якщо ви потім запитуєте шматок на 20 байт, аллокатор поверне найостанніший звільнений шматок з голови fastbin.
|
||||
Example:
|
||||
```c
|
||||
char *a = malloc(20);
|
||||
char *b = malloc(20);
|
||||
@ -45,18 +41,89 @@ b = malloc(20); // c
|
||||
c = malloc(20); // b
|
||||
d = malloc(20); // a
|
||||
```
|
||||
---
|
||||
### 🔥 Сучасні розгляди glibc (tcache ≥ 2.26)
|
||||
|
||||
З glibc 2.26 кожен потік зберігає свій власний **tcache**, який запитується *перед* несортованим біном. Тому сценарій першого підходу буде **досягнуто лише якщо**:
|
||||
|
||||
1. Запитуваний розмір є **більшим за `tcache_max`** (0x420 на 64-біт за замовчуванням), *або*
|
||||
2. Відповідний бін tcache є **вже заповненим або очищеним вручну** (шляхом виділення 7 елементів і їх використання).
|
||||
|
||||
У реальних експлойтах ви зазвичай додасте допоміжну процедуру, таку як:
|
||||
```c
|
||||
// Drain the tcache for a given size
|
||||
for(int i = 0; i < 7; i++) pool[i] = malloc(0x100);
|
||||
for(int i = 0; i < 7; i++) free(pool[i]);
|
||||
```
|
||||
Якщо tcache вичерпано, наступні звільнення потрапляють до несортованого бін і класична поведінка first-fit (пошук з хвоста, вставка в голову) може бути знову активована.
|
||||
|
||||
---
|
||||
### 🚩 Створення UAF з перекриттям з first-fit
|
||||
|
||||
Фрагмент нижче (перевірено на glibc 2.38) показує, як спліттер у несортованому біні може бути зловжито для створення 2 **перекриваючих вказівників** – потужного примітиву, який перетворює одне звільнення на запис-після-звільнення.
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(){
|
||||
setbuf(stdout, NULL);
|
||||
|
||||
/* 1. prepare 2 adjacent chunks and free the first one */
|
||||
char *A = malloc(0x420); // big enough to bypass tcache
|
||||
char *B = malloc(0x420);
|
||||
strcpy(A, "AAAA\n");
|
||||
free(A); // A → unsorted
|
||||
|
||||
/* 2. request a *smaller* size to force a split of A */
|
||||
char *C = malloc(0x400); // returns lower half of former A
|
||||
|
||||
/* 3. The remainder of A is still in the unsorted bin.
|
||||
Another 0x400-byte malloc will now return the *same*
|
||||
region pointed to by B – creating a UAF/overlap. */
|
||||
char *C2 = malloc(0x400);
|
||||
|
||||
printf("B = %p\nC2 = %p (overlaps B)\n", B, C2);
|
||||
|
||||
// Arbitrary write in B is immediately visible via C2
|
||||
memset(B, 'X', 0x10);
|
||||
fwrite(C2, 1, 0x10, stdout); // prints Xs
|
||||
}
|
||||
```
|
||||
Рецепт експлуатації (поширений у недавніх CTF):
|
||||
|
||||
1. **Витягніть** tcache для цільового розміру.
|
||||
2. **Звільніть** шматок, щоб він потрапив у несортований бін.
|
||||
3. **Виділіть** трохи менший розмір – аллокатор розділяє несортований шматок.
|
||||
4. **Виділіть** знову – залишкова частина перекривається з існуючим використовуваним шматком → UAF.
|
||||
5. Перезапишіть чутливі поля (вказівники на функції, FILE vtable тощо).
|
||||
|
||||
Практичний приклад можна знайти у виклику *Setjmp* 2024 HITCON Quals, де цей точний примітив використовується для переходу від UAF до повного контролю над `__free_hook`.{{#ref}}
|
||||
../../../../references/2024_setjmp_firstfit.md
|
||||
{{#endref}}
|
||||
|
||||
---
|
||||
### 🛡️ Заходи захисту та зміцнення
|
||||
|
||||
* **Безпечне з'єднання (glibc ≥ 2.32)** захищає лише односпрямовані списки *tcache*/**fastbin**. Несортовані/малі/великі біни все ще зберігають сирі вказівники, тому перекриття на основі першого підходу залишаються життєздатними, якщо ви можете отримати витік купи.
|
||||
* **Шифрування вказівників купи та MTE** (ARM64) поки не впливають на x86-64 glibc, але прапори зміцнення дистрибутиву, такі як `GLIBC_TUNABLES=glibc.malloc.check=3`, призупинять виконання при несумісних метаданих і можуть зламати наївні PoC.
|
||||
* **Заповнення tcache при звільненні** (пропоновано у 2024 для glibc 2.41) ще більше зменшить використання несортованих; слідкуйте за майбутніми випусками під час розробки загальних експлойтів.
|
||||
|
||||
---
|
||||
## Інші посилання та приклади
|
||||
|
||||
- [**https://heap-exploitation.dhavalkapil.com/attacks/first_fit**](https://heap-exploitation.dhavalkapil.com/attacks/first_fit)
|
||||
- [**https://8ksec.io/arm64-reversing-and-exploitation-part-2-use-after-free/**](https://8ksec.io/arm64-reversing-and-exploitation-part-2-use-after-free/)
|
||||
- ARM64. Використання після звільнення: створити об'єкт користувача, звільнити його, створити об'єкт, який отримує звільнений шматок і дозволяє записувати в нього, **перезаписуючи позицію user->password** з попереднього. Повторно використати користувача, щоб **обійти перевірку пароля**
|
||||
- ARM64. Використання після звільнення: створіть об'єкт користувача, звільніть його, створіть об'єкт, який отримує звільнений шматок і дозволяє записувати в нього, **перезаписуючи позицію user->password** з попереднього. Повторно використайте користувача, щоб **обійти перевірку пароля**.
|
||||
- [**https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/use_after_free/#example**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/use_after_free/#example)
|
||||
- Програма дозволяє створювати нотатки. Нотатка міститиме інформацію про нотатку в malloc(8) (з вказівником на функцію, яку можна викликати) і вказівник на інший malloc(\<size>) з вмістом нотатки.
|
||||
- Атака полягатиме в створенні 2 нотаток (note0 і note1) з більшим вмістом malloc, ніж розмір інформації про нотатку, а потім їх звільненні, щоб вони потрапили в швидкий бін (або tcache).
|
||||
- Потім створити ще одну нотатку (note2) з розміром вмісту 8. Вміст буде в note1, оскільки шматок буде повторно використано, де ми можемо змінити вказівник функції, щоб вказувати на функцію win, а потім використати Use-After-Free для note1, щоб викликати новий вказівник функції.
|
||||
- Програма дозволяє створювати нотатки. Нотатка міститиме інформацію про нотатку в malloc(8) (з вказівником на функцію, яку можна викликати) і вказівник на інший malloc(<size>) з вмістом нотатки.
|
||||
- Атака полягатиме в створенні 2 нотаток (note0 і note1) з більшим вмістом malloc, ніж розмір інформації про нотатку, а потім звільнити їх, щоб вони потрапили в швидкий бін (або tcache).
|
||||
- Потім створіть ще одну нотатку (note2) з розміром вмісту 8. Вміст буде в note1, оскільки шматок буде повторно використано, де ми можемо змінити вказівник функції, щоб вказувати на функцію win, а потім використати Use-After-Free для виклику нового вказівника функції.
|
||||
- [**https://guyinatuxedo.github.io/26-heap_grooming/pico_areyouroot/index.html**](https://guyinatuxedo.github.io/26-heap_grooming/pico_areyouroot/index.html)
|
||||
- Можливо виділити деяку пам'ять, записати бажане значення, звільнити його, повторно виділити, і оскільки попередні дані все ще там, їх оброблять відповідно до нової очікуваної структури в шматку, що робить можливим встановлення значення для отримання прапора.
|
||||
- Можливо виділити деяку пам'ять, записати бажане значення, звільнити його, повторно виділити, і оскільки попередні дані все ще там, їх буде оброблено відповідно до нової очікуваної структури в шматку, що робить можливим встановлення значення для отримання прапора.
|
||||
- [**https://guyinatuxedo.github.io/26-heap_grooming/swamp19_heapgolf/index.html**](https://guyinatuxedo.github.io/26-heap_grooming/swamp19_heapgolf/index.html)
|
||||
- У цьому випадку потрібно записати 4 всередині конкретного шматка, який є першим, що виділяється (навіть після примусового звільнення всіх з них). У кожному новому виділеному шматку його номер в індексі масиву зберігається. Потім виділити 4 шматки (+ початково виділений), останній буде містити 4 всередині, звільнити їх і примусово повторно виділити перший, який використовуватиме останній звільнений шматок, що містить 4 всередині нього.
|
||||
- У цьому випадку потрібно записати 4 всередині конкретного шматка, який є першим, що виділяється (навіть після примусового звільнення всіх з них). У кожному новому виділеному шматку його номер у масиві індексується. Потім виділіть 4 шматки (+ початково виділений), останній буде містити 4 всередині, звільніть їх і примусово повторно виділіть перший, який використовуватиме останній звільнений шматок, що містить 4 всередині.
|
||||
- 2024 HITCON Quals Setjmp write-up (Quarkslab) – практична атака на перекриття першого підходу / несортованого розподілу: <https://ctftime.org/writeup/39355>
|
||||
- Angstrom CTF 2024 *heapify* write-up – зловживання розподілом несортованого біна для витоку libc та отримання перекриття: <https://hackmd.io/@aneii11/H1S2snV40>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user