data base file是什么文件_IO文件及利用源码大量

重新分析:

ac9e40e582c97940a1b3d0a133582341.png

主要问题在于memcpy拷贝到stdin中,stdin是什么

// libio/libio.hstruct _IO_FILE {  int _flags;        /* High-order word is _IO_MAGIC; rest is flags. */#define _IO_file_flags _flags  /* The following pointers correspond to the C++ streambuf protocol. */  /* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */  char* _IO_read_ptr;    /* Current read pointer */  char* _IO_read_end;    /* End of get area. */  char* _IO_read_base;    /* Start of putback+get area. */  char* _IO_write_base;    /* Start of put area. */  char* _IO_write_ptr;    /* Current put pointer. */  char* _IO_write_end;    /* End of put area. */  char* _IO_buf_base;    /* Start of reserve area. */  char* _IO_buf_end;    /* End of reserve area. */  /* The following fields are used to support backing up and undo. */  char *_IO_save_base; /* Pointer to start of non-current get area. */  char *_IO_backup_base;  /* Pointer to first valid character of backup area */  char *_IO_save_end; /* Pointer to end of non-current get area. */  struct _IO_marker *_markers;  struct _IO_FILE *_chain;  int _fileno;#if 0  int _blksize;#else  int _flags2;#endif  _IO_off_t _old_offset; /* This used to be _offset but it's too small.  */#define __HAVE_COLUMN /* temporary */  /* 1+column number of pbase(); 0 is unknown. */  unsigned short _cur_column;  signed char _vtable_offset;  char _shortbuf[1];  /*  char* _save_gptr;  char* _save_egptr; */  _IO_lock_t *_lock;#ifdef _IO_USE_OLD_IO_FILE};struct _IO_FILE_complete{  struct _IO_FILE _file;#endif#if defined _G_IO_IO_FILE_VERSION && _G_IO_IO_FILE_VERSION == 0x20001  _IO_off64_t _offset;# if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T  /* Wide character stream stuff.  */  struct _IO_codecvt *_codecvt;  struct _IO_wide_data *_wide_data;//延申数据  struct _IO_FILE *_freeres_list;  void *_freeres_buf;# else  void *__pad1;  void *__pad2;  void *__pad3;  void *__pad4;# endif  size_t __pad5;  int _mode;  /* Make sure we don't get into trouble again.  */  char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];#endif};extern struct _IO_FILE_plus _IO_2_1_stdin_;//只要存在FILE 必然会有这三个结构体extern struct _IO_FILE_plus _IO_2_1_stdout_;extern struct _IO_FILE_plus _IO_2_1_stderr_;
/* Extra data for wide character streams.  */struct _IO_wide_data{  wchar_t *_IO_read_ptr;    /* Current read pointer */  wchar_t *_IO_read_end;    /* End of get area. */  wchar_t *_IO_read_base;    /* Start of putback+get area. */  wchar_t *_IO_write_base;    /* Start of put area. */  wchar_t *_IO_write_ptr;    /* Current put pointer. */  wchar_t *_IO_write_end;    /* End of put area. */  wchar_t *_IO_buf_base;    /* Start of reserve area. */  wchar_t *_IO_buf_end;        /* End of reserve area. */  /* The following fields are used to support backing up and undo. */  wchar_t *_IO_save_base;    /* Pointer to start of non-current get area. */  wchar_t *_IO_backup_base;    /* Pointer to first valid character of                   backup area */  wchar_t *_IO_save_end;    /* Pointer to end of non-current get area. */  __mbstate_t _IO_state;  __mbstate_t _IO_last_state;  struct _IO_codecvt _codecvt;  wchar_t _shortbuf[1];  const struct _IO_jump_t *_wide_vtable;};

stdin stdout stderr 三个是分别指向三个结构体的指针;即:

_IO_2_1_stderr__IO_2_1_stdout__IO_2_1_stdin_
// libio/libioP.hstruct _IO_jump_t{    JUMP_FIELD(size_t, __dummy);    JUMP_FIELD(size_t, __dummy2);    JUMP_FIELD(_IO_finish_t, __finish);    JUMP_FIELD(_IO_overflow_t, __overflow);    JUMP_FIELD(_IO_underflow_t, __underflow);    JUMP_FIELD(_IO_underflow_t, __uflow);    JUMP_FIELD(_IO_pbackfail_t, __pbackfail);    /* showmany */    JUMP_FIELD(_IO_xsputn_t, __xsputn);    JUMP_FIELD(_IO_xsgetn_t, __xsgetn);    JUMP_FIELD(_IO_seekoff_t, __seekoff);    JUMP_FIELD(_IO_seekpos_t, __seekpos);    JUMP_FIELD(_IO_setbuf_t, __setbuf);    JUMP_FIELD(_IO_sync_t, __sync);    JUMP_FIELD(_IO_doallocate_t, __doallocate);    JUMP_FIELD(_IO_read_t, __read);    JUMP_FIELD(_IO_write_t, __write);    JUMP_FIELD(_IO_seek_t, __seek);    JUMP_FIELD(_IO_close_t, __close);    JUMP_FIELD(_IO_stat_t, __stat);    JUMP_FIELD(_IO_showmanyc_t, __showmanyc);    JUMP_FIELD(_IO_imbue_t, __imbue);#if 0    get_column;    set_column;#endif};/* We always allocate an extra word following an _IO_FILE.   This contains a pointer to the function jump table used.   This is for compatibility with C++ streambuf; the word can   be used to smash to a pointer to a virtual function table. */struct _IO_FILE_plus{  _IO_FILE file;  const struct _IO_jump_t *vtable;};

FILE结构通过chain域形成链条,链表头部用_IO_list_all表示

通过伪造结构体,更改vtable指针 vtable指针指向_IO_jump_t结构体

保存一个虚表,记录实际调用函数地址

FILE结构体

源码真好看也是真恶心7e7fe07909cdf1110e855e93e3a3cac1.png

https://www.bookstack.cn/read/CTF-All-In-One/doc-4.13_io_file.md#FILE%20%E7%BB%93%E6%9E%84

fread()函数,实现

// libio/iofread.c_IO_size_t_IO_fread (void *buf, _IO_size_t size, _IO_size_t count, _IO_FILE *fp){  _IO_size_t bytes_requested = size * count;  _IO_size_t bytes_read;  CHECK_FILE (fp, 0);  if (bytes_requested == 0)    return 0;  _IO_acquire_lock (fp);  bytes_read = _IO_sgetn (fp, (char *) buf, bytes_requested);   // 调用 _IO_sgetn 函数  _IO_release_lock (fp);  return bytes_requested == bytes_read ? count : bytes_read / size;}

函数通过调用_IO_sgetn实现

_IO_sgetn

// libio/genops.c_IO_size_t_IO_sgetn (_IO_FILE *fp, void *data, _IO_size_t n){  /* FIXME handle putback buffer here! */  return _IO_XSGETN (fp, data, n);          // 调用宏 _IO_XSGETN???}

e... 再调用宏????

// libio/libioP.h#define _IO_JUMPS_FILE_plus(THIS) \  _IO_CAST_FIELD_ACCESS ((THIS), struct _IO_FILE_plus, vtable)#if _IO_JUMPS_OFFSET# define _IO_JUMPS_FUNC(THIS) \ (*(struct _IO_jump_t **) ((void *) &_IO_JUMPS_FILE_plus (THIS) \               + (THIS)->_vtable_offset))# define _IO_vtable_offset(THIS) (THIS)->_vtable_offset#else# define _IO_JUMPS_FUNC(THIS) _IO_JUMPS_FILE_plus (THIS)# define _IO_vtable_offset(THIS) 0#endif#define JUMP2(FUNC, THIS, X1, X2) (_IO_JUMPS_FUNC(THIS)->FUNC) (THIS, X1, X2)#define _IO_XSGETN(FP, DATA, N) JUMP2 (__xsgetn, FP, DATA, N)

哦,这个熟,在vtable指向的那个表_IO_jump_t里有这个东东也有JUMP的类似函数,最终调用函数;那个函数就不写了;

类似的fwrite也是如此;

--------------

大概清楚IO的实现流程,看看攻击方式:

FSOP:

通过劫持_IO_list_all_,伪造链表,在检测到内存错误,执行exit ,main函数返回时执行_IO_flush_all_lockp() 从而getshell

shit。。。

// libio/genops.cint_IO_flush_all_lockp (int do_lock){  int result = 0;  struct _IO_FILE *fp;  int last_stamp;#ifdef _IO_MTSAFE_IO  __libc_cleanup_region_start (do_lock, flush_cleanup, NULL);  if (do_lock)    _IO_lock_lock (list_all_lock);#endif  last_stamp = _IO_list_all_stamp;  fp = (_IO_FILE *) _IO_list_all;   // 将其覆盖为伪造的链表  while (fp != NULL)    {      run_fp = fp;      if (do_lock)    _IO_flockfile (fp);      if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)   // 条件#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T       || (_IO_vtable_offset (fp) == 0           && fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr                    > fp->_wide_data->_IO_write_base))#endif       )      && _IO_OVERFLOW (fp, EOF) == EOF)     // fp 指向伪造的 vtable    result = EOF;      if (do_lock)    _IO_funlockfile (fp);      run_fp = NULL;      if (last_stamp != _IO_list_all_stamp)    {      /* Something was added to the list.  Start all over again.  */      fp = (_IO_FILE *) _IO_list_all;      last_stamp = _IO_list_all_stamp;    }      else    fp = fp->_chain;    // 指向下一个 IO_FILE 对象    }#ifdef _IO_MTSAFE_IO  if (do_lock)    _IO_lock_unlock (list_all_lock);  __libc_cleanup_region_end (0);#endif  return result;}
// libio/libioP.h#define _IO_OVERFLOW(FP, CH) JUMP1 (__overflow, FP, CH)#define _IO_WOVERFLOW(FP, CH) WJUMP1 (__overflow, FP, CH)

在以上三种情况下函数调用流程

malloc_printerr -> __libc_message -> __GI_abort -> _IO_flush_all_lockp -> _IO_OVERFLOW

libc-2.24后更新防御机制

所有的vtable放入一个单独的段,任何间接跳转时检查 vtable是否在段中,如果不在则_IO_vtable_check一下,确认是否在必要时终止进程;

即不能通过改写v伪造vtablee2ddc3cb6a377bcafd5011d9f825d19c.pnge2ddc3cb6a377bcafd5011d9f825d19c.png

额,大概这样,更深一步具体认识应该在wp出来后再看。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值