初音未来の消失

_IO_file_ attack(2.24)

_IOfile attack(2.24)

glibc 2.24

glic 2.23 IO_file attack

glibc 2.23 下,可以通过伪造 __IO_file_plus 来劫持函数调用链,而这个
漏洞在 glibc 2.24 之后被修复了。

现在的 glibc 在调用虚函数之前,会对 vtable 地址的合法性。

static inline const struct _IO_jump_t *
IO_validate_vtable (const struct _IO_jump_t *vtable)
{
  uintptr_t section_length = __stop___libc_IO_vtables - __start___libc_IO_vtables;
  const char *ptr = (const char *) vtable;
  uintptr_t offset = ptr - __start___libc_IO_vtables;
  if (__glibc_unlikely (offset >= section_length))
    _IO_vtable_check ();//引发报错的函数
  return vtable;
}

利用方式

IO_str_jumpsIO_wstr_jumps 这两个结构体 可以绕过 vtable check

其中,利用 IO_str_jumps 绕过更简单,IO_wstr_jumps 利用方式也差不多。

const struct _IO_jump_t _IO_str_jumps libio_vtable =
{
  JUMP_INIT_DUMMY,//调试发现占0x10
  JUMP_INIT(finish, _IO_str_finish),
  JUMP_INIT(overflow, _IO_str_overflow),
  JUMP_INIT(underflow, _IO_str_underflow),
  JUMP_INIT(uflow, _IO_default_uflow),
[...]
};

_IO_str_finsh 的源代码:

void _IO_str_finish (FILE *fp, int dummy)
{
  if (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF))
    (((_IO_strfile *) fp)->_s._free_buffer) (fp->_IO_buf_base);  //call qword ptr [fp+0E8h]
  fp->_IO_buf_base = NULL;
  _IO_default_finish (fp, 0);
}

只要绕过

  1. fp -> _flags == 0
  2. fp -> _IO_buf_base > 0

的 check, 程序就能调用 (((_IO_strfile *) fp)->_s._free_buffer) ,也就是 fp+0xe8 的函数

exp 构造

  1. fp->_flags = 0
  2. vtable = _IO_str_jumps - 0x8 (因为系统会调用 vtable + 0x20 处的函数,_IO_str_jumps - 0x8 + 0x20 = _IO_str_overfflow )
  3. fp->_IO_buf_base = /bin/sh_addr
  4. fp+0xe8 = system_addr

Reference

https://www.anquanke.com/post/id/168802#h3-6

退出移动版