Skip to content

FILE vtable hijack (_IO_validate_vtable bypass)

Bir FILE'ın vtable'ını legitimate in-range bir jump table'a (örn. _IO_str_jumps) işaret ettir; böylece glibc'nin _IO_validate_vtable section check'ini geçer, handler'ı ise attacker-controlled ikincil bir call'a ulaşır.

Mechanism

Note

glibc 2.24, _IO_vtable_check / IO_validate_vtable'ı ekledi: herhangi bir vtable dispatch'inden önce FILE'ın vtable pointer'ı read-only __libc_IO_vtables section'ı içinde bulunmalıdır (bu section'daki array symbol'ü sibling notlarda geçen __io_vtables'tır; sınır kontrolü vtable - __start___libc_IO_vtables < section boyutu), aksi halde slow path __libc_fatal üzerinden abort eder. Güvenlik sınırı "yalnızca kutsanmış vtable'lar çağrılabilir"dir. Bypass, sıfırdan yeni bir vtable forge etmez; handler'ı ardından FILE'ın attacker-controlled bir field'ı üzerinden ikinci, check'lenmemiş bir indirect call yapan gerçek bir in-range tabloyu yeniden kullanır. Örneğin _IO_str_jumps_IO_str_overflow, fp+0xe0'daki allocator pointer'ını çağırır ve _IO_str_finish fp+0xe8'i çağırır; wide tablo _IO_wfile_jumps, _wide_data->_wide_vtable'a ulaşır (House of Apple 2). Range check geçer çünkü primary vtable legitimate'tir; control flow, check'in asla kapsamadığı ikincil dispatch'te çalınır.

Walkthrough

Ulaşılabilir biçim (glibc libio/strops.c, genops.c):

/* _IO_str_overflow effectively calls: */
new_buf = (char *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size);
/* _allocate_buffer lives at fp+0xe0, not range-checked */

Kavramsal reçete:

  1. libc'yi leak'le; &_IO_str_jumps'ı hesapla (in-range, check'i geçer).
  2. Forge edilmiş/corrupt edilmiş FILE'ın vtable = &_IO_str_jumps'ını set et.
  3. Operasyonu/flush'ı, _IO_str_overflow (ya da _IO_str_finish) dispatch edilen slot olacak şekilde düzenle.
  4. Gömülü function pointer'ını (fp+0xe0 / fp+0xe8) system/one_gadget'a set et ve arg'ı şekillendir (örn. bir "/bin/sh" pointer'ı).
  5. FILE-flush path'i üzerinden tetikle (fsop-via-io-list-all-io-flush-all-lockp.md).

Warning

Field offset'leri ve tam olarak ulaşılabilir handler glibc sürümüne göre değişir; sonraki release'ler _IO_str/wide path'lerinin parçalarını sertleştirdi. Target libc'ye karşı doğrula.

Detection

  • Program'ın bir string/wide stream olarak hiç oluşturmadığı, _IO_str_jumps/_IO_wfile_jumps taşıyan heap-resident bir FILE.
  • .text dışına işaret eden ikincil dispatch (fp+0xe0, _wide_vtable).
  • Başarısız bir vtable check'inde tetiklenen __libc_fatal/abort (probing göstergesi).

Mitigation

  • __libc_IO_vtables'ı read-only tut (zaten enforce ediliyor) ve validation'ı ikincil dispatch pointer'larına genişlet.
  • libio indirect call'ları üzerinde CFI / -fcf-protection.
  • ASLR ve info-leak önleme; _IO_str/wide overflow handler'larını sertleştir.

References