Skip to content

Pure-Call Oriented Programming

Control flow'u sürmek için bir dispatcher kullanarak call ile biten ( ret ya da jmp yerine) gadget'ları zincirleyen bir code-reuse modeli — GNU libc gadget'larıyla Turing-complete olduğu gösterilmiştir (glibc proof-of-concept olarak kullanıldı; model glibc'ye özgü değildir).

Mechanism

Invariant

Klasik code-reuse saldırıları, bir control-transfer instruction ile biten kısa instruction sequence'ları ("gadget"ler) zincirler: ROP ret-terminated gadget'lar kullanır, JOP indirect jmp-terminated gadget'lar kullanır. Savunmalar ve detector'lar genelde bu terminator'lara bakar (örn. shadow stack'ler ret'i izler; gadget-frequency heuristic'leri yoğun ret/jmp chain'lerini işaretler).

Pure-Call Oriented Programming (PCOP) bu varsayımı kaldırır: her fonksiyonel gadget bir indirect call ile biter. Güvenlik açısından önemli özellik şudur: bir call sadece bir jump değildir — stack'e bir return address push eder ve çağrılan sequence'ın kendisi başka side effect'ler içerebilir. PCOP'un katkısı (a) call-terminated gadget'ların nasıl keşfedileceğini, (b) push edilen return address'in side effect'lerinin nasıl nötralize edileceğini ya da soğurulacağını ve (c) bunların, attacker-controlled bir index/table'ı ilerleten bir dispatcher gadget üzerinden nasıl zincirleneceğini göstermesidir — JOP'un dispatcher'ına benzer ama call'lar için. Yazarlar uygun call-gadget'ların GNU libc içinde mevcut olduğunu ve ortaya çıkan modelin Turing-complete olduğunu bildiriyor.

Savunma açısından neden önemli: yalnızca ret/jmp edge'lerini kısıtlayan ya da chaining'i kısıtlamadan call target'larını whitelist'leyen bir control-flow-integrity veya anti-ROP şeması, tamamen call edge'leriyle ifade edilen bir saldırıyla atlatılabilir. İndirgenmiş bir "TinyCOP" varyantının, güncel code-reuse savunmalarına daha da dirençli olduğu anlatılır.

PCOP ≠ COP. Bunu klasik Call-Oriented Programming (Carlini et al., 2015) ile karıştırma: COP, coarse-grained CFI'yı, return address'ini overwrite eden bir dispatcher fonksiyon (memcpy gibi) ile bypass etmeye odaklanır. PCOP (Sadeghi & Niksefat, 2017) ise her gadget'ın indirect call ile bittiği "pure" modeli ve push edilen return-address side effect'lerinin nötralizasyonu üzerinden Turing-completeness'i ele alır.

Walkthrough

Kavramsal yapı (somut gadget adresleri yok — bunlar binary/versiyona özgüdür):

[ functional gadget ]  ... ; call [reg/mem]   -> performs one operation, then transfers
[ dispatcher gadget ]  advance index; call next_gadget_from_table

Bir PCOP kurgusunun izlediği high-level adımlar:

  1. Gadget kataloğu. Hedef bir image'da (örn. libc) faydalı bir primitive yapan ve indirect call ile biten sequence'ları tara, örtük return-address push'unun side effect'ini kaydet.
  2. Dispatcher. Her iterasyonda attacker-controlled bir table'dan sonraki gadget pointer'ını okuyup onu call eden bir gadget seç — chain'i bir araya dizen motor.
  3. Side-effect yönetimi. Her call bir return address push ettiğinden, layout'lar bu push'ları tolere etmeli ya da tüketmelidir (ROP "padding" qword'lerini hesaba katmanın muadili).
  4. Kompozisyon. Arbitrary computation'ı ifade etmek için arithmetic/load/store/branch gadget'larını birleştir (Turing-completeness iddiası).

Kavramsal katalog girdisi

Bu girdi bilinçli olarak high-level'dir. PCOP, turnkey bir exploit değil, expressiveness'in akademik bir gösterimidir; gadget set'i, dispatcher ve table layout'u tamamen hedef binary ve toolchain'e özgüdür. Bir tarif değil, call-only savunmaların neden önemli olduğunu anlamak için bir model olarak ele al.

Detection

  • Fonksiyonların ortasına ya da non-function-entry adreslere giden indirect call edge'leri — call-gadget reuse'un alameti; coarse-grained CFI ve branch-target telemetry bunları işaretleyebilir.
  • Doğal call/return eşleşmesi olmadan, kısa ve arka arkaya indirect call'ların anormal yüksek sıklığı (call-chain yoğunluğu).
  • Shadow-stack uyuşmazlıkları PCOP için ROP'a kıyasla daha az bilgi verir, bu yüzden savunmacılar yalnızca ret-only monitoring'e güvenmemeli.

Mitigation

  • Indirect-call target'larını geçerli function entry'lerine kısıtlayan fine-grained / forward-edge CFI, "call into gadget" adımını kırar.
  • Intel CET — IBT (Indirect Branch Tracking), indirect call/jmp target'larının ENDBR-marked olmasını gerektirir, çoğu mid-function call gadget'ını kaldırır.
  • Compile/link zamanında gadget-reduction ve ASLR/PIE (böylece gadget/table adresleri bir leak olmadan bilinmez).

References

Ayrıca bkz: call-oriented-programming, jump-oriented-programming, return-oriented-programming.