Skip to content

_IO_wfile_jumps

Forge edilmiş bir FILE'ın vtable'ını in-range _IO_wfile_jumps'a ayarla ve _IO_wfile_overflow'u tetikle ki _IO_wdoallocbuf attacker-controlled bir _wide_data->_wide_vtable'ı dereference etsin (House of Apple 2).

Mechanism

Note

_IO_wfile_jumps, wide-character file stream'lerin vtable'ıdır ve __io_vtables içinde durur, dolayısıyla ona yönelen forge edilmiş bir FILE glibc 2.24 range check'ini geçer. _IO_wfile_overflow'u tetiklemek şunu çalıştırır: wide write buffer unallocated ise (fp->_wide_data->_IO_write_base == NULL) _IO_wdoallocbuf(f)'i çağırır, o da _IO_WDOALLOCATE(fp) macro'sunu invoke eder → fp->_wide_data->_wide_vtable->__doallocate'i dereference eder. Kritik nokta: _wide_data ve onun ikincil _wide_vtable_IO_vtable_check range test'ine tabi değildir. __doallocate slot'u system olan, tamamen attacker-controlled bir _wide_vtable (FILE/buffer öyle ayarlanmış ki argument "/bin/sh" olur) arbitrary bir call verir — bu, baskın modern FSOP technique'i olan House of Apple 2'nin çekirdeğidir.

Walkthrough

Erişilebilir path (glibc libio/wfileops.c, wgenops.c):

wint_t _IO_wfile_overflow (FILE *f, wint_t wch) {
  ...
  if (f->_wide_data->_IO_write_base == NULL) {
    _IO_wdoallocbuf (f);                     /* if wide buffer unallocated */
    ...
  }
}

void _IO_wdoallocbuf (FILE *fp) {
  if (fp->_wide_data->_IO_buf_base) return;
  if (!(fp->_flags & _IO_UNBUFFERED))
    if ((wint_t) _IO_WDOALLOCATE (fp) != WEOF)   /* -> _wide_vtable->__doallocate */
      return;
  ...
}
/* _IO_WDOALLOCATE(fp) == fp->_wide_data->_wide_vtable->__doallocate(fp) */

House of Apple 2 reçetesi:

  1. vtable = &_IO_wfile_jumps (in range; check'i geçer, bkz. io-vtable-check-bypass.md) olan bir FILE forge et.
  2. _flags'i öyle ayarla ki _IO_UNBUFFERED clear olsun ve overflow/_wdoallocbuf path'i çalışsın; _wide_data'yı _IO_buf_base == NULL ve _IO_write_base == NULL olan kontrollü bir region'a ayarla.
  3. _wide_data->_wide_vtable__doallocate entry'si system olan fake bir table'a yönelt ve "/bin/sh"'e bir pointer'ı, fp'nin (ilk argument) call'ı faydalı kıldığı yere yerleştir (genelde _flags field'ının " sh;" tarzı string'lerle overlap etmesi yoluyla).
  4. exit/abort sırasında _IO_flush_all_lockp üzerinden tetikle (fsop-via-io-list-all-io-flush-all-lockp.md).

Warning

_wide_data'nın field offset'leri ve _wide_vtable slot index'i glibc versiyonları arasında değişir; target libc'ye karşı doğrula. Bazı 2.36+ hardening'ler wide path'in parçalarını pointer-guard'lar.

Detection

  • _IO_wdoallocbuf/_IO_WDOALLOCATE'ten non-allocator bir adrese giden indirect call.
  • Flush list'inde _IO_wfile_jumps kullanan, heap'e işaret eden bir _wide_vtable'a sahip FILE.

Mitigation

  • 2.24 range check'i _wide_vtable'ı kapsamaz; sonraki glibc wide path'in parçalarına guarding ekler. İkincil vtable call'u üzerindeki CFI yapısal çözümdür.

References