Skip to content

wide vtable bypass (_IO_wfile_jumps)

glibc ana FILE vtable'ını doğrulamaya başladıktan sonra, attacker'lar wide-character kod path'i (_IO_wfile_jumps) üzerinden pivot eder; bunun iç içe geçmiş _wide_data->_wide_vtable pointer'ı aynı _IO_vtable_check'e tabi tutulmaz — House of Apple 2'nin temeli.

Mechanism

Suistimal edilen invariant: vtable doğrulaması yalnızca birincil FILE vtable'ını korur, ulaşabildiği wide vtable'ı değil

glibc, FILE-stream exploitation'ı _IO_vtable_check() ekleyerek sertleştirdi: fp->vtable üzerinden dispatch etmeden önce glibc, pointer'ın bilinen, salt okunur __libc_IO_vtables region'ının içine düştüğünü doğrular. Bu, fp->vtable'ı keyfi bir fake table'a yönelten naif vtable-hijacking'i bloklar.

Boşluk yapısaldır. _IO_wfile_jumps, wide (wchar_t) stream'leri için kullanılan meşru, range içinde bir vtable'dır, dolayısıyla fp->vtable'ı ona yöneltmek _IO_vtable_check'i geçer. Ama wide path daha sonra ikinci, iç içe bir vtable üzerinden dispatch eder: fp->_wide_data->_wide_vtable. O pointer, attacker'ın etkilediği bir _IO_wide_data yapısından okunur ve birincil vtable'ın yeniden doğrulandığı gibi yeniden doğrulanmaz. Kavramsal olarak:

/* primary dispatch — validated */
_IO_vtable_check();           /* fp->vtable must be in libc range */
_IO_wfile_overflow(fp, ...);  /* a legitimate in-range slot       */
  -> _IO_wdoallocbuf(fp);
     -> _IO_WDOALLOCATE(fp);  /* == fp->_wide_data->_wide_vtable->doallocate */
        /* ^ wide vtable pointer NOT checked -> attacker-controlled call */

Yani attacker, birincil pointer için gerçek bir libc vtable'ı seçerek check'i karşılar, ardından kontrolü birkaç call daha derinde doğrulanmamış wide vtable üzerinden kaçırır. Bu, House of Apple 2'nin çekirdek fikridir.

Walkthrough

Public House of Apple yazılarını izleyen üst düzey reproduction. Bir FILE yapısı üzerinde arbitrary write varsaymaktadır (sahte bir _IO_FILE_plus ya da FSOP ile ulaşılan stderr / bir _IO_list_all entry'si).

  1. Birincil vtable'ı wide jump table'a yönelt. fp->vtable_IO_wfile_jumps adresine ayarla (libc'de, böylece _IO_vtable_check karşılanır). Offset'i, tetikleyen işlem _IO_wfile_overflow'a düşecek şekilde seç.

  2. wide-data pointer'ını controlled belleğe yönelt. fp->_wide_data'yı (_IO_FILE içindeki offset) attacker-controlled belleğe ayarla ve o fake _IO_wide_data içinde _wide_vtable'ı, doallocate slot'u (_IO_WDOALLOCATE hedefi) istenen function pointer'ı (örneğin system ya da register-controlling bir pivot için setcontext+61) tutan bir fake table'a ayarla.

  3. Allocation path'ini zorla. FILE flag'lerini/buffer alanlarını, overflow handler'ının bir wide buffer allocate etmek zorunda kalacağı şekilde düzenle: _IO_wfile_overflow -> _IO_wdoallocbuf -> _IO_WDOALLOCATE, ki bu _wide_data->_wide_vtable->doallocate(fp) çağırır — fp'nin ilk argüman olduğu, kontrol edilmeyen, attacker'ın seçtiği bir call.

trigger flush/overflow
  -> fp->vtable (=_IO_wfile_jumps, IN RANGE, passes check)
     -> _IO_wfile_overflow -> _IO_wdoallocbuf -> _IO_WDOALLOCATE
        -> fp->_wide_data->_wide_vtable->doallocate(fp)   // NOT validated
Diğer FILE teknikleriyle ilişki

Aynı doğrulanmamış wide-vtable gözlemi, bir "house of …" FILE saldırıları ailesinin temelinde yatar. İlk argüman fp olduğu için, final call'u setcontext ya da bir stack pivot ile eşleştirmek, tek bir controlled call'u tam kod yürütmeye dönüştürür. Bkz. io-vtable-check-bypass ve house-of-apple-2.

Detection

  • Runtime'da vtable bütünlüğü: vtable_IO_wfile_jumps olan ama _wide_data / _wide_vtable'ı libc dışını (heap/bss'e) gösteren bir FILE object anormaldir; _IO_list_all'u gezen ve her iki vtable katmanını doğrulayan tooling bunu yakalar.
  • Crash imzaları: _IO_wdoallocbuf / _IO_wfile_overflow içinde libc dışı bir call hedefiyle fault'lar ya da __libc_message abort'ları wide-path suistimaline işaret eder. Core'larda/EDR backtrace'lerinde yakala.
  • Öncül write: stderr/FILE yapılarına ya da _IO_list_all'a (FSOP giriş noktası) yapılan write'ları izlemek, kurulum aşamasını işaretler.
  • CI: ASan/heap-debug build'leri FILE object'inin altta yatan overwrite'ını yakalar.

Mitigation

  • Yapısal düzeltme, doğrulamayı wide vtable'a genişletmektir; defender'lar _IO_wfile_* path'lerini sertleştiren glibc sürümlerini takip etmeli ve glibc'yi güncel tutmalıdır.
  • Erişilebilir corrupt edilebilir FILE pointer'larını kaldırmak (freed/UAF FILE object'leri bırakmaktan kaçın; arbitrary write'ı düzelt), giriş koşulunu ortadan kaldırır.
  • Genel hardening — CET/shadow stack, test'te ASan/MTE, -D_FORTIFY_SOURCE=2 — maliyeti artırır ve öncül corruption'ı yakalar.
  • Defense-in-depth: her indirect call'u (yalnızca birincil vtable'ı değil) kontrol eden pointer-integrity / CFI şemaları, bu tekniğin dayandığı asimetriyi kapatır.

References