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_vtablepointer'ı 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).
-
Birincil vtable'ı wide jump table'a yönelt.
fp->vtable'ı_IO_wfile_jumpsadresine ayarla (libc'de, böylece_IO_vtable_checkkarşılanır). Offset'i, tetikleyen işlem_IO_wfile_overflow'a düşecek şekilde seç. -
wide-data pointer'ını controlled belleğe yönelt.
fp->_wide_data'yı (_IO_FILEiçindeki offset) attacker-controlled belleğe ayarla ve o fake_IO_wide_dataiçinde_wide_vtable'ı,doallocateslot'u (_IO_WDOALLOCATEhedefi) istenen function pointer'ı (örneğinsystemya da register-controlling bir pivot içinsetcontext+61) tutan bir fake table'a ayarla. -
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_jumpsolan 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_overflowiçinde libc dışı bir call hedefiyle fault'lar ya da__libc_messageabort'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.