Skip to content

Intel CET Shadow Stack Bypass via Counterfeit Objects

Counterfeit Object-Oriented Programming (COOP): mevcut tüm C++ virtual fonksiyonlarını meşru vtable call site'ları üzerinden chain'le; böylece hiçbir return address bozulmaz ve CET shadow stack tamamen atlatılır.

Mechanism

Neden çalışır

CET shadow stack'i tam olarak tek bir şeyi korur: backward edge'i. Bir RET, korumalı return-address kopyasına karşı kontrol edilir. COOP, attacker-controlled bir RET'i hiç çalıştırmayarak kazanır — hesaplamasını tamamen, programın zaten meşru biçimde aldığı forward edge'lerden inşa eder.

  • Attacker counterfeit C++ object'leri forge eder: seçilmiş bir vptr artı birkaç seçilmiş data alanı, attacker-controlled bellekte (örn. heap overflow veya use-after-free yoluyla) yerleştirilir. Her sahte nesnenin vptr'si gerçek bir vtable'ı gösterir, böylece mevcut bir virtual call gerçek bir virtual fonksiyona dispatch eder.
  • Chain, bir main-loop gadget (ML-G) tarafından sürülür: object pointer'ların bir container/array'i üzerinde iterate eden ve her birinde bir virtual method çağıran gerçek bir virtual fonksiyon — örneğin bir loop veya bir container destructor'ı. Attacker, o container'ı counterfeit object'lerden oluşan bir array'e işaret ettirerek tek bir meşru call site'ının attacker'ın seçtiği bir virtual fonksiyon dizisini (vfgadget'leri) çağırmasını sağlar.
  • Destekleyici vfgadget'ler işi yapar: ARITH-G/W-G, counterfeit object alanlarını örtüştürerek aritmetik ve memory write yapar; böylece bir gadget'ın output alanı sonraki gadget'ın input'una alias olur; LOAD-R64-G x64'te argument register'larını set eder; ML-ARG-G x86'da argument'ları member değişkenleri üzerinden geçirir; REC-G recursion sağlar.
  • Kritik olarak, her transfer gerçek bir vtable slot'u üzerinden gerçek bir virtual-function girişine yapılan bir indirect CALL'dur. Bozuk bir return address yoktur (shadow stack her callee içinde eşleşmiş CALL/RET çiftleri görür) ve off-pad iniş yoktur (her virtual fonksiyon girişi geçerli bir ENDBR'dır, dolayısıyla kaba IBT da geçer).

Bypass invariant'ı: backward edge'e dayalı bir savunma, tamamen meşru forward virtual call'lar olarak ifade edilmiş bir hesaplamayı göremez. Shadow stack'in eşleşmiş-çift garantisi sağlanırken attacker yine de Turing-complete kontrol elde eder.

Walkthrough

Bu, yayımlanmış COOP yapısı üzerine kavramsal bir akıl yürütmedir; onu turnkey bir exploit olarak değil, bir attacker'ın izlediği tarif olarak değerlendir.

1. Hedef call site (bir ML-G) zaten mevcuttur — object pointer'ların bir container'ı üzerindeki bir loop içindeki bir virtual call:

// existing program code (simplified)
for (auto *o : objects)      // attacker controls 'objects' storage
    o->vfunc();              // indirect CALL [vtable+slot] -> real virtual fn

2. Attacker counterfeit object'leri yerleştirir, böylece loop seçilmiş bir vfgadget dizisini dispatch eder ve alanlar data flow için örtüşecek şekilde düzenlenir:

objects[0] -> {vptr=&Vtbl_A, f0=...}   // ARITH-G: writes into objects[1].f0
objects[1] -> {vptr=&Vtbl_B, f0=...}   // W-G:    stores to attacker target
objects[2] -> {vptr=&Vtbl_C, ...}      // LOAD-R64-G: load arg regs, then call
...

3. Loop'u tetikle. Her iterasyon normal bir virtual dispatch'tir:

CALL  qword ptr [rax]        ; rax = counterfeit vptr -> real virtual function
... function executes, RET matches its own CALL (shadow stack: OK) ...
; loop advances to next counterfeit object, repeat

Hiçbir RET attacker-injected koda return etmez; shadow stack hiçbir uyuşmazlık görmez.

Backward-edge savunmaları bunu neden kaçırır

Shadow Stack yalnızca her RET'in korumalı kopyayla eşleştiğini doğrular — burada doğrudur, çünkü attacker kendi caller'larına return eden bütün fonksiyonları yeniden kullanır. Düz IBT de geçer: virtual-function girişleri COOP'un kullandığı tek hedef tipi olan ENDBR'ı taşır. COOP'un Turing-complete olduğu gösterildi ve gerçek hedeflere (IE10, Firefox 36) karşı demonstre edildi; döneminin birkaç C++-aware CFI savunmasını yendi.

Mitigation

(Artık risk / onu gerçekte ne durdurur.) COOP, shadow stack veya kaba IBT tarafından durdurulmaz. Çıtayı yükselten şey, belirli bir indirect/virtual call site'ının hangi fonksiyona ulaşabileceğini sınırlayan forward-edge type checking'dir: FineIBT ve Clang CFI'nin vcall/type-id kontrolleri, hedef tipi call site'la eşleşmeyen bir counterfeit vptr'yi reddeder ve vfgadget kümesini çökertir. Object-type-integrity / vtable-protection şemaları benzer biçimde dispatch'ten önce runtime tipini doğrular. CET'e karşı ilgili whole-function reuse için ayrıca daha geniş COOP-for-CET-bypass ve block-oriented programming ailelerine bak.

References