Source code (bootlin)
_IO_FILE_plus & _IO_FILE_complete_plus
struct _IO_FILE_plus
{
FILE file;
const struct _IO_jump_t *vtable;
};
#ifdef _IO_USE_OLD_IO_FILE
/* This structure is used by the compatibility code as if it were an
_IO_FILE_plus, but has enough space to initialize the _mode argument
of an _IO_FILE_complete. */
struct _IO_FILE_complete_plus
{
struct _IO_FILE_complete file;
const struct _IO_jump_t *vtable;
};
#endif
_IO_FILE & _IO_FILE_complete
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_FILE_complete
{
struct _IO_FILE _file;
#endif
__off64_t _offset;
/* Wide character stream stuff. */
struct _IO_codecvt *_codecvt;
struct _IO_wide_data *_wide_data;
struct _IO_FILE *_freeres_list;
void *_freeres_buf;
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)];
};
_flags
#define _IO_MAGIC 0xFBAD0000 /* Magic number */
#define _IO_MAGIC_MASK 0xFFFF0000
#define _IO_USER_BUF 0x0001 /* Don't deallocate buffer on close. */
#define _IO_UNBUFFERED 0x0002
#define _IO_NO_READS 0x0004 /* Reading not allowed. */
#define _IO_NO_WRITES 0x0008 /* Writing not allowed. */
#define _IO_EOF_SEEN 0x0010
#define _IO_ERR_SEEN 0x0020
#define _IO_DELETE_DONT_CLOSE 0x0040 /* Don't call close(_fileno) on close. */
#define _IO_LINKED 0x0080 /* In the list of all open files. */
#define _IO_IN_BACKUP 0x0100
#define _IO_LINE_BUF 0x0200
#define _IO_TIED_PUT_GET 0x0400 /* Put and get pointer move in unison. */
#define _IO_CURRENTLY_PUTTING 0x0800
#define _IO_IS_APPENDING 0x1000
#define _IO_IS_FILEBUF 0x2000
/* 0x4000 No longer used, reserved for compat. */
#define _IO_USER_LOCK 0x8000
_IO_jump_t
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);
#if 0
get_column;
set_column;
#endif
};
_IO_file_jumps
[IO_FILE_JUMPS] = {
JUMP_INIT_DUMMY,
JUMP_INIT (finish, _IO_file_finish),
JUMP_INIT (overflow, _IO_file_overflow),
JUMP_INIT (underflow, _IO_file_underflow),
JUMP_INIT (uflow, _IO_default_uflow),
JUMP_INIT (pbackfail, _IO_default_pbackfail),
JUMP_INIT (xsputn, _IO_file_xsputn),
JUMP_INIT (xsgetn, _IO_file_xsgetn),
JUMP_INIT (seekoff, _IO_new_file_seekoff),
JUMP_INIT (seekpos, _IO_default_seekpos),
JUMP_INIT (setbuf, _IO_new_file_setbuf),
JUMP_INIT (sync, _IO_new_file_sync),
JUMP_INIT (doallocate, _IO_file_doallocate),
JUMP_INIT (read, _IO_file_read),
JUMP_INIT (write, _IO_new_file_write),
JUMP_INIT (seek, _IO_file_seek),
JUMP_INIT (close, _IO_file_close),
JUMP_INIT (stat, _IO_file_stat),
JUMP_INIT (showmanyc, _IO_default_showmanyc),
JUMP_INIT (imbue, _IO_default_imbue)
},
_IO_wfile_jumps
[IO_WFILE_JUMPS] = {
JUMP_INIT_DUMMY,
JUMP_INIT (finish, _IO_new_file_finish),
JUMP_INIT (overflow, (_IO_overflow_t) _IO_wfile_overflow),
JUMP_INIT (underflow, (_IO_underflow_t) _IO_wfile_underflow),
JUMP_INIT (uflow, (_IO_underflow_t) _IO_wdefault_uflow),
JUMP_INIT (pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
JUMP_INIT (xsputn, _IO_wfile_xsputn),
JUMP_INIT (xsgetn, _IO_file_xsgetn),
JUMP_INIT (seekoff, _IO_wfile_seekoff),
JUMP_INIT (seekpos, _IO_default_seekpos),
JUMP_INIT (setbuf, _IO_new_file_setbuf),
JUMP_INIT (sync, (_IO_sync_t) _IO_wfile_sync),
JUMP_INIT (doallocate, _IO_wfile_doallocate),
JUMP_INIT (read, _IO_file_read),
JUMP_INIT (write, _IO_new_file_write),
JUMP_INIT (seek, _IO_file_seek),
JUMP_INIT (close, _IO_file_close),
JUMP_INIT (stat, _IO_file_stat),
JUMP_INIT (showmanyc, _IO_default_showmanyc),
JUMP_INIT (imbue, _IO_default_imbue)
},
AAR - write() ing to Arbitrary Memory
- _flags = 0xfbad0800
- _IO_read_end = _IO_write_base
- _IO_write_base = target address to write
- _IO_write_ptr = target address + length
- _fileno = stdout(1)
- call fwrite, fputs ...
AAW - read() ing to Arbitrary Memory
- _flags = 0xfbad2488
- _IO_read_ptr = read_end
- _IO_ buf_base = target address to read
- _IO_ buf_end = target address + length
- _IO_ buf_end - _IO_ buf_base >= number of bytes to read
- _fileno = stdin(0)
- call fread, fgets ...
vtable overwrite
- _IO_FILE_plus.vtable = fake_vtable
- _lock = address_ptr (writable && has NULL value)
- but, morden glibc versions validate vtable function
validate vtable bypass (_IO_wfile_overflow)
- _IO_FILE_plus.wide_data = fake_vtable
- _IO_FILE_plus.vtable = _IO_wfile_overflow - call offset
- _IO_wfile_overflow -> _IO_wdoallocbuf -> call rax (rax is fake_vtable)
// _IO_wdoallocbuf+36
mov rax, qword ptr [rax+0xe0]
call qword ptr [rax+0x68] // call any function
info leak (fclose)
- _flags = 0xfbad0840 (
- _IO_read_end = _IO_write_base
- _IO_write_base = target address to write
- _IO_write_ptr = target address + length
- _fileno = stdout(1)
- call fclose
info leak (stdin/stdout)
- _flags = 0xfbad1800
- _IO_read_ptr = 0x0
- _IO_read_end = 0x0
- _IO_read_base = 0x0
- _IO_write_base = 0x0
- _IO_write_ptr = the first byte is 0x00
- call fgets ... / fflush, fputs ...
https://ssongkit.tistory.com/271
https://pwn.college/software-exploitation/file-struct-exploits
https://pwnable-study.tistory.com/43
'background > linux' 카테고리의 다른 글
[pwn.college] Format String Bug (0) | 2024.05.06 |
---|---|
[pwn.college] Return Oriented Programming (1) | 2024.05.02 |
[how2heap] Tcache Poisoning (glibc 2.31/2.35) (0) | 2024.04.10 |
[how2heap] House of Botcake (glibc 2.31) (0) | 2024.03.18 |
[how2heap] Fastbin dup into stack (glibc 2.35) (1) | 2024.03.11 |