File Structure Note
FILE Structure
FILE Structs in glibc
- _IO_FILE_PLUS structure

source
1 | struct _IO_FILE_plus |
- _IO_FILE
https://elixir.bootlin.com/glibc/glibc-2.40/source/libio/bits/types/struct_FILE.h#L49
1 | struct _IO_FILE |
- _IO_jump_t
https://elixir.bootlin.com/glibc/glibc-2.40/source/libio/libioP.h#L294
1 | struct _IO_jump_t |
- _IO_FILE_complete
https://elixir.bootlin.com/glibc/glibc-2.40/source/libio/bits/types/struct_FILE.h#L85
1 | struct _IO_FILE_complete |
- _IO_FILE_complete_plus
https://elixir.bootlin.com/glibc/glibc-2.40/source/libio/libioP.h#L335
1 | struct _IO_FILE_complete_plus |
- Magic Numbers
1 | /* Magic number and bits for the _flags field. The magic number is |
how vtable call function?
- example:
_IO_doallocate
expand the macro
https://elixir.bootlin.com/glibc/glibc-2.40/source/libio/libioP.h#L222
https://elixir.bootlin.com/glibc/glibc-2.40/source/libio/libioP.h#L124
1 |
https://elixir.bootlin.com/glibc/glibc-2.40/source/libio/libioP.h#L108
1 |
in libc 2.24+ IO_validate_vtable will check if the vtable is legal (RO vtable section)
https://elixir.bootlin.com/glibc/glibc-2.40/source/libio/libioP.h#L1022
1 | IO_validate_vtable (const struct _IO_jump_t *vtable) |
FSOP
before glibc 2.34 just do malloc/free hook hijack
but in newer versions it was not been used anymore
_IO_wfile_overflow() →_IO_wdoallocbuf()
- glibc 2.40
- craft fake
_IO_2_1_stdout_

vfprintf_internal
https://elixir.bootlin.com/glibc/glibc-2.40/source/stdio-common/vfprintf-internal.c#L1521
1 | int |
from done = Xprintf(buffer_to_file_done) (&wrap);
jump to __printf_buffer_to_file_done
__printf_buffer_to_file_done
https://elixir.bootlin.com/glibc/glibc-2.40/source/stdio-common/printf_buffer_to_file.c#L116
1 | int |
__printf_buffer_flush_to_file
https://elixir.bootlin.com/glibc/glibc-2.40/source/stdio-common/printf_buffer_to_file.c#L48
1 | void |

wanted to call _IO_sputn which is vtable+0x38 but we can lead it into _IO_wfile_overflow also a legal segment


_IO_wfile_overflow
https://elixir.bootlin.com/glibc/glibc-2.40/source/libio/wfileops.c#L406
1 | wint_t |
our final target is to call _IO_wdoallocbuf that we can control the fake vtable without checking the vtable
rdi is the _flags also used as the system parameter
_flags & _IO_NO_WRITES== 0
*rdi & 0x8 = 0

_flags & _IO_CURRENTLY_PUTTING== 0
*rdi & 0x0800 = 0_wide_data->_IO_write_base== 0_wide_data+0x28= 0
example: 0x00007ffff7fb3560+0x28=0
_IO_wdoallocbuf
https://elixir.bootlin.com/glibc/glibc-2.40/source/libio/wgenops.c#L364
1 | void |
fp->_wide_data->_IO_buf_base==0_wide_data+0x40=0_flags & _IO_UNBUFFERED==0*rdi & 0x0002= 0call _IO_WDOALLOCATE (fp)
which is_wide_data->_wide_vtable->_IO_doallocate_t
hijack it into system function*(*(_wide_data+0xe0)+0x68)=system
call system(_flags)
final exploit
summarize the requirements
*vtable=_IO_wfile_overflow-0x38, change the offset depend on the function it going to call-0x38is_IO_sputn_flags & 0x8= 0_flags & 0x800= 0_flags & 0x2= 0_wide_data+0x28= 0_wide_data+0x40= 0*(*(_wide_data+0xe0)+0x68)=system_mode=0xffffffff
fake _IO_2_1_stdout_
1 | def libc(adr): |
References
https://www.cnblogs.com/LynneHuan/p/17822091.html#利用_io_wfile_overflow函数控制程序执行流
https://hackmd.io/@naup96321/SyvhbZWYR
https://tttang.com/archive/1345/
https://www.mrskye.cn/archives/221/