Vtable Hijack
concept
in newer version of libc, we can no longer overwrite the file->vtable
address with our fake vtable, this because libc has introduced a mitigation IO_validate_vtable
that will check whether the vtable that is stored in the FILE
is in the correct region or not.
_wide_data
is a struct which is similar to _IO_FILE
which is created to handle WCHAR
or unicodes. Both struct have vtables, _wide_data
uses _IO_wfile_jumps
vtable while _IO_FILE
uses _IO_file_jumps
.
There's two macro that is being used to call these methods within the vtables:
_IO_JUMPS_FUNC
_IO_WIDE_JUMPS_FUNC
the IO_validate_vtable
mitigation only exist in the _IO_JUMPS_FUNC
macro.
one thing to note is that _IO_wfile_jumps.__overflow
method will eventually calls file->_wide_data->_wide_vtable->__doallocate
.
This if way we can:
file->vtable = file->_wide_data->_wide_vtable
file->_wide_data->_wide_vtable = &fake_wide_vtable
and because the calls to _wide_data->_wide_vtable
don't have any checks, we can take control of execution.
fwrite
summary
Set
f->flags
to_IO_MAGIC & ~_IO_CURRENTLY_PUTTING & ~_IO_UNBUFFERED
which is0xFBAD0000 & ~0x0800 & ~0x0002
Set
f->wide_data
to a controllable fakewide_data
Set
f->wide_data->_IO_buf_base
andf->wide_data->_IO_write_base
to 0x0Set
f->vtable
to_IO_wfile_jumps
Set
f->wide_data->wide_vtable
to a controllabe fakewide_vtable
Set
f->wide_data->wide_vtable->__doallocate
tosystem
orwin
note:
If space is limited, fake
wide_data
and fakewide_vtable
can be overlappedmake sure
f->_lock
contains a valid address that points to NULL
call trace
we can start from it's definition and implementation:
which then calls _IO_sputn()
which is a jump to __xsputn
section of the f->vtable
and assuming, we have overwritten f->vtable
with _IO_WIDE_JUMPS_FUNC
it will call _IO_wfile_xsputn()
which then calls _IO_wdefault_xsputn()
which then calls __woverflow()
when calls _IO_OVERFLOW ();
again, remember we have overwritten f->vtable
with _IO_WIDE_JUMPS_FUNC
and because of it the __overflow
section of f->vtable
will refer to _IO_wfile_overflow()
and so the execution continues from there on
assuming we set the correct f->flags
and other requirement it will eventually call _IO_wdoallocbuf()
again, setting the correct requirements that satisfied the if statements will call _IO_WDOALLOCATE()
which will then call f->wide_data->wide_vtable->__doallocate
. and since its within our control, we control the execution.
others
todo
Last updated