_IOfile attack(2.24)
glibc 2.24
在 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_jumps 和 IO_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);
}只要绕过
- fp -> _flags == 0
- fp -> _IO_buf_base > 0
的 check, 程序就能调用 (((_IO_strfile *) fp)->_s._free_buffer) ,也就是 fp+0xe8 的函数
exp 构造
- fp->_flags = 0
- vtable = _IO_str_jumps - 0x8 (因为系统会调用 vtable + 0x20处的函数,_IO_str_jumps - 0x8 + 0x20 = _IO_str_overfflow)
- fp->_IO_buf_base = /bin/sh_addr
- fp+0xe8 = system_addr



 
    
Comments | NOTHING