Stack Pivoting - EBP2Ret - EBP chaining
Last updated
Last updated
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Esta técnica explora a capacidade de manipular o Base Pointer (EBP) para encadear a execução de múltiplas funções através do uso cuidadoso do registrador EBP e da sequência de instruções leave; ret
.
Como lembrete, leave
basicamente significa:
And as the EBP está na pilha antes do EIP, é possível controlá-lo controlando a pilha.
Esta técnica é particularmente útil quando você pode alterar o registrador EBP, mas não tem uma maneira direta de mudar o registrador EIP. Ela aproveita o comportamento das funções quando terminam de executar.
Se, durante a execução de fvuln
, você conseguir injetar um EBP falso na pilha que aponte para uma área na memória onde o endereço do seu shellcode está localizado (mais 4 bytes para contabilizar a operação pop
), você pode controlar indiretamente o EIP. Quando fvuln
retorna, o ESP é definido para esta localização criada, e a operação pop
subsequente diminui o ESP em 4, efetivamente fazendo com que aponte para um endereço armazenado pelo atacante ali.
Note como você precisa saber 2 endereços: O onde o ESP vai, onde você precisará escrever o endereço que é apontado pelo ESP.
Primeiro, você precisa saber um endereço onde pode escrever dados / endereços arbitrários. O ESP apontará aqui e executará o primeiro ret
.
Então, você precisa saber o endereço usado pelo ret
que irá executar código arbitrário. Você poderia usar:
Um endereço válido ONE_GADGET.
O endereço de system()
seguido de 4 bytes de lixo e o endereço de "/bin/sh"
(x86 bits).
O endereço de um gadget jump esp;
(ret2esp) seguido do shellcode a ser executado.
Alguma cadeia ROP.
Lembre-se de que antes de qualquer um desses endereços na parte controlada da memória, deve haver 4
bytes por causa da parte pop
da instrução leave
. Seria possível abusar desses 4B para definir um segundo EBP falso e continuar controlando a execução.
Há uma variante específica dessa técnica conhecida como "Exploit Off-By-One". É usada quando você pode apenas modificar o byte menos significativo do EBP. Nesse caso, a localização da memória que armazena o endereço para pular com o ret
deve compartilhar os três primeiros bytes com o EBP, permitindo uma manipulação semelhante com condições mais restritas.
Geralmente, modifica-se o byte 0x00 para pular o mais longe possível.
Além disso, é comum usar um RET sled na pilha e colocar a verdadeira cadeia ROP no final para tornar mais provável que o novo ESP aponte dentro do RET SLED e a cadeia ROP final seja executada.
Portanto, colocando um endereço controlado na entrada EBP
da pilha e um endereço para leave; ret
no EIP
, é possível mover o ESP
para o endereço EBP
controlado da pilha.
Agora, o ESP
está controlado apontando para um endereço desejado e a próxima instrução a ser executada é um RET
. Para abusar disso, é possível colocar no lugar controlado do ESP isto:
&(próximo EBP falso)
-> Carregar o novo EBP por causa do pop ebp
da instrução leave
system()
-> Chamado pelo ret
&(leave;ret)
-> Chamado após o término do sistema, moverá o ESP para o EBP falso e começará novamente
&("/bin/sh")
-> Parâmetro para system
Basicamente, dessa forma é possível encadear vários EBPs falsos para controlar o fluxo do programa.
Isso é como um ret2lib, mas mais complexo sem benefício aparente, mas pode ser interessante em alguns casos extremos.
Além disso, aqui você tem um exemplo de um desafio que usa essa técnica com um leak de pilha para chamar uma função vencedora. Este é o payload final da página:
Como explicado neste post, se um binário é compilado com algumas otimizações, o EBP nunca consegue controlar o ESP, portanto, qualquer exploit que funcione controlando o EBP basicamente falhará porque não tem nenhum efeito real. Isso ocorre porque o prólogo e epílogo mudam se o binário estiver otimizado.
Não otimizado:
Otimizado:
pop rsp
Nesta página você pode encontrar um exemplo usando esta técnica. Para este desafio, era necessário chamar uma função com 2 argumentos específicos, e havia um gadget pop rsp
e há um leak da pilha:
Verifique a técnica ret2esp aqui:
Ret2esp / Ret2reg64 bits, exploração off by one com uma cadeia rop começando com um ret sled
64 bits, sem relro, canário, nx e pie. O programa concede um leak para stack ou pie e um WWW de um qword. Primeiro obtenha o leak da stack e use o WWW para voltar e obter o leak do pie. Em seguida, use o WWW para criar um loop eterno abusando das entradas de .fini_array
+ chamando __libc_csu_fini
(mais informações aqui). Abusando dessa escrita "eterna", uma cadeia ROP é escrita na .bss e acaba chamando-a fazendo pivot com RBP.
No ARM64, o prólogo e epílogo das funções não armazenam e recuperam o registro SP na pilha. Além disso, a instrução RET
não retorna ao endereço apontado pelo SP, mas para o endereço dentro de x30
.
Portanto, por padrão, apenas abusando do epílogo você não conseguirá controlar o registro SP sobrescrevendo alguns dados dentro da pilha. E mesmo que você consiga controlar o SP, ainda precisaria de uma maneira de controlar o registro x30
.
prólogo
epílogo
A maneira de realizar algo semelhante ao stack pivoting no ARM64 seria ser capaz de controlar o SP
(controlando algum registro cujo valor é passado para SP
ou porque por algum motivo SP
está pegando seu endereço da pilha e temos um overflow) e então abusar do epílogo para carregar o registro x30
de um SP
controlado e RET
para ele.
Além disso, na página seguinte você pode ver o equivalente de Ret2esp no ARM64:
Ret2esp / Ret2regAprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)