Ret2esp / Ret2reg
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Porque o ESP (Ponteiro de Pilha) sempre aponta para o topo da pilha, esta 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 logo 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 Address Space Layout Randomization (ASLR) não estiver habilitado 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 dentro do próprio programa vulnerável por essas instruções (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 com o shellcode. Essa interferência poderia ocorrer se o shellcode fosse colocado no meio da pilha da função.
Se você estiver sem espaço para escrever após sobrescrever o RIP (talvez apenas alguns bytes), escreva um shellcode inicial jmp
como:
E escreva o shellcode cedo na pilha.
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:
Você pode ver outro exemplo dessa técnica em https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html. Há um buffer overflow sem NX habilitado, é usado um gadget para reduzir o endereço de $esp
e então um jmp esp;
para pular para o shellcode:
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 pode ser usado (ret2reg).
Você pode encontrar alguns exemplos aqui:
strcpy
irá armazenar em eax
o endereço do buffer onde o shellcode foi armazenado e eax
não está sendo sobrescrito, então é possível usar um ret2eax
.
No ARM64 não há instruções que permitem pular para o registrador SP. Pode ser possível encontrar um gadget que move sp para um registrador e então pula para esse registrador, mas na libc da minha kali não consegui encontrar nenhum gadget assim:
Os únicos que descobri mudariam o valor do registro onde sp foi copiado antes de pular para ele (então se tornaria inútil):
Se um registro tiver um endereço interessante, é possível pular para ele apenas encontrando a instrução adequada. Você poderia usar algo como:
Em ARM64, é x0
que armazena o valor de retorno de uma função, então pode ser que x0 armazene o endereço de um buffer controlado pelo usuário com um shellcode para executar.
Exemplo de código:
Verificando a desassemblagem da função, é possível ver que o endereço do buffer (vulnerável a bof e controlado pelo usuário) é armazenado em x0
antes de retornar do buffer overflow:
Também é possível encontrar o gadget br x0
na função do_stuff
:
Usaremos esse gadget para pular para ele porque o binário é compilado SEM PIE. Usando um padrão, é possível ver que o offset do buffer overflow é 80, então o exploit seria:
Se em vez de fgets
fosse usado algo como read
, seria 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
isso não funciona porque adiciona um byte nulo (0x00) no final.
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.
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)