Skip to content

FSOP via _IO_list_all / _IO_flush_all_lockp

exit/abort sırasında glibc, _IO_flush_all_lockp içinde _IO_list_all stream chain'ini dolaşır ve her FILE'ın vtable'ı üzerinden _IO_OVERFLOW çağırır; _IO_list_all'ı sahte bir FILE'a overwrite etmek kontrollü bir vtable call sürer.

Mechanism

Note

File Stream Oriented Programming (FSOP), glibc'nin normal teardown'unu suistimal eder. exit() sırasında, main'den dönüşte veya abort() sırasında, _IO_cleanup_IO_flush_all_lockp singly-linked _IO_list_all listesini (her FILE'ın _chain'i üzerinden) iterate eder ve pending output'u olan herhangi bir stream için _IO_OVERFLOW(fp, EOF)'u vtable üzerinden çağırır. Security boundary, stream listesinin ve dispatch ettiği vtable'ın bütünlüğüdür. _IO_list_all'ı (klasik olarak bir unsorted-bin veya large-bin attack ile) writable memory'deki sahte bir _IO_FILE_plus'a işaret edecek şekilde overwrite ederek saldırgan, process teardown'ında hangi object'in — ve hangi vtable'ın — invoke edileceğini kontrol eder, ek bir trigger gerekmeden.

Walkthrough

Ulaşılabilir koşul (glibc libio/genops.c, _IO_flush_all_lockp):

for (fp = (FILE *) _IO_list_all; fp != NULL; fp = fp->_chain)
  if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base))
      && _IO_OVERFLOW (fp, EOF) == EOF)   /* vtable dispatch */
    result = EOF;

Kavramsal tarif:

  1. libc base'i ve bir arbitrary write (veya bir bin-attack write primitive) elde et.
  2. _IO_list_all'ı heap'teki sahte bir FILE'a işaret edecek şekilde overwrite et.
  3. Sahte FILE'da flush koşulunun geçmesi için _mode <= 0 ve _IO_write_ptr > _IO_write_base ayarla.
  4. Sahte vtable_IO_OVERFLOW saldırgan koduna resolve olacak şekilde ayarla — 2.24 öncesi doğrudan; 2.24 sonrası bir vtable-range bypass ile birleştir (file-vtable-hijack.md, House of Apple).
  5. Normal exit/abort veya main return ile tetikle — _IO_cleanup_IO_flush_all_lockp listesini yürür ve sahte FILE'ın _IO_OVERFLOW'unu vtable üzerinden dispatch eder. (House of Orange, bu _IO_list_all overwrite'ını bir unsorted-bin attack ile sağlayan ayrı bir primitive'tir — corrupt bir top chunk üzerinden malloc'ta abort'u zorlar; ama bu primitive için şart değil, large-bin attack vb. de _IO_list_all overwrite'ı için kullanılabilir.)

Warning

glibc 2.24'ten beri naif "vtable = system" yaklaşımı _IO_vtable_check tarafından engellenir; modern FSOP bunu in-range bir vtable (_IO_str_jumps/_IO_wfile_jumps) ile eşleştirir.

Detection

  • vtable__libc_IO_vtables dışında olan veya alanları gerçek bir stream ile tutarsız olan heap-resident FILE struct'ları.
  • Bilinen stdio FILE'larına referans vermeyen _IO_list_all head veya _chain pointer'ları.
  • _IO_list_all adresini hedefleyen unsorted/large-bin bk/fd write'ları.

Mitigation

  • glibc 2.24+ vtable whitelist'i (_IO_vtable_check) naif sahte vtable'ları engeller.
  • Heap-integrity hardening (tcache/unsorted-bin check'leri, safe-linking) _IO_list_all'ı overwrite eden write primitive'ini azaltır.
  • Full RELRO/ASLR ve info-leak önleme.

References