IO_FILE leak
_IO_FILE_plus的结构如下(glibc-2.33 libioP.h)
struct _IO_FILE_plus
{
FILE file;
const struct _IO_jump_t *vtable;
};
在libc-2.23版本中,有个全局变量_IO_list_all,该变量指向了FILE链表的头部,我们可以通过gdb动态调试来实际观察一下。首先认识一个结构体_IO_FILE_plus
_IO_list_all的结构如下(glibc-2.23 libioP.h)
extern struct _IO_FILE_plus *_IO_list_all;
_IO_FILE_plus的结构如下(glibc-2.23 libioP.h)
struct _IO_FILE_plus
{
_IO_FILE file;
const struct _IO_jump_t *vtable;
};
_IO_jump_t的结构如下(glibc-2.23 libioP.h)
struct _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);
在glibc-2.23版本下libio.h中_IO_FILE的结构如下(glibc-233中找了好几圈没找到)
struct _IO_FILE {
int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
IO_FILE leak|利用IO_FILE进行leak
在pwn题中,当遇到没有可以用来泄露的功能时,我们一般将堆块分配到stdout指针处存储的_IO_2_1_stdout_该IO_FILE结构体处,修改其_flags为0xfbad1800,将后面三个read指针置空,将_IO_write_base处的第一个字节改为0x58,后面的_IO_write_ptr和_IO_write_end保持不变。之后当程序遇到puts函数时就会打印_IO_write_base到_IO_write_ptr之间的内容,按照上面步骤改动的话,我们泄露出的第一个libc地址是_IO_file_jumps。 常用的payload如下所示,至于为啥需要flags=0xfbad1800(flags也可以是0xfbad3887),这里分析起来十分复杂,可以参见puts源码,只能说为了达到输出效果需要这样设置,另外该flags这样设置只是针对puts函数,其余打印函数略有不同。
payload = p64(0xfbad1800)+p64(0)*3+b"\x58"
另外payload也可以这样写,这样泄露出来的第一个地址将会是_IO_2_1_stdin_。
payload = p64(0xfbad3887)+p64(0)*3+p8(0)

浙公网安备 33010602011771号