Skip to content

JOP under IBT-disabled userspace

Jump-Oriented Programming, functional gadget'ları ret yerine indirect jmp/call ve bir dispatcher gadget aracılığıyla chain'ler, dolayısıyla bir shadow stack'i hiç tetiklemez — ve CET Indirect Branch Tracking'in (IBT) userspace'te devre dışı veya yok olduğu her yerde tamamen geçerli kalır.

Mechanism

Neden çalışır

CET, control-flow integrity'yi iki yarıya böler: shadow stack backward edge'leri (RET) korur ve IBT, her indirect hedefin ENDBR64 ile başlamasını gerektirerek forward edge'leri (indirect JMP/CALL) korur. JOP bu boşlukta yaşar: yalnızca forward edge'leri kullanır ve IBT'nin kapalı olduğu platformlarda o forward edge kısıtlanmamıştır.

  • Jump-Oriented Programming'de (Bletsch, Jiang, Freeh & Liang, ASIACCS 2011) attacker stack'i ve RET'i tamamen terk eder. Functional gadget'lar — asıl işi yapan dizilimler — ret ile değil, bir indirect jmp/call ile biter.
  • Kontrol bir dispatcher gadget tarafından sıralanır: gadget adreslerinden oluşan bir dispatch table boyunca bir virtual program counter'ı ilerletir ve bir sonrakine atlar. Klasik bir biçim add edx, 4; jmp dword ptr [edx]'dir — table pointer'ını artır, kendi indirect jump'ıyla kontrolü dispatcher'a geri veren bir sonraki functional gadget'a atla.
  • Hiçbir RET çalışmadığı için, shadow stack hiç danışılmaz: tespit edilecek bir return-address uyuşmazlığı yoktur. Bir CET shadow stack (user veya supervisor) saf bir JOP chain'ine karşı hiçbir şey yapmaz.
  • Forward edge yalnızca IBT etkinse kontrol edilir. Linux'ta IBT kernel için etkindir ama userspace process'leri için değil (non-ENDBR binary'lerle geriye dönük uyumluluk), dolayısıyla userspace indirect jump'ları kısıtlanmamıştır. IBT'nin açık olduğu yerlerde bile fonksiyonlar endbr64 ile başlar, dolayısıyla fonksiyon entry point'lerine (veya herhangi bir endbr64-prefix'li konuma) atlayan bir dispatcher yine de IBT kontrolünü geçer — kaba taneli IBT her call site'ın hangi geçerli hedefe ulaşabileceğini sabitlemez.

Invariant: bir shadow stack yalnızca RET'in ne okuduğunu kısıtlar. JOP hiç return etmez, dolayısıyla onunla yürütme arasında duran tek şey forward-edge CFI'dır — ve IBT-disabled userspace'te bu yoktur.

Walkthrough

1. Forward edge'in korumasız olduğunu doğrula. -fcf-protection ile derlenmiş bir userspace binary'si endbr64 marker'ları taşır, ama platform onu enforce etmedikçe process IBT kapalı çalışır:

$ readelf -n ./target | grep -a IBT
      Properties: x86 feature: IBT, SHSTK
$ objdump -d ./target | grep -m1 endbr64
  1149:  f3 0f 1e fa    endbr64        ; valid indirect-branch landing pad

GNU-property note'u binary'nin IBT'yi desteklediğini söyler; enforce edilip edilmediği bir runtime/kernel kararıdır ve userspace IBT genellikle etkin değildir.

2. Dispatch table'ı ve bir dispatcher gadget'ı hazırla. Dispatcher table'da gezinir ve her functional gadget'a devreder:

; dispatcher gadget (advance virtual PC, jump to next gadget)
add  edx, 4
jmp  dword ptr [edx]      ; edx -> dispatch table of functional-gadget addresses

; a functional gadget ends in an indirect branch back to control
pop  eax
jmp  dword ptr [esi]      ; returns flow to the dispatcher, not via RET

3. Shadow stack neden sessiz kalır. Chain yalnızca jmp/call çalıştırır; hiç RET verilmez, dolayısıyla hiçbir shadow-stack karşılaştırması olmaz ve hiçbir #CP fault'u ateşlenmez. Saldırı, user shadow stack tamamen etkin olsa bile başarılı olur.

JOP'u gerçekte ne durdurur

Bunu yalnızca forward-edge CFI durdurur: IBT'yi etkinleştirmek (böylece indirect branch'ler ENDBR64'ü hedeflemeli) ve ideal olarak her call site'ı meşru hedef kümesine kısıtlayan fine-grained CFI — FineIBT, Clang CFI veya kernel CFI. Kaba IBT tek başına yine de herhangi bir endbr64'e atlamaya izin verir, dolayısıyla geçerli entry point'lerin JOP/COOP tarzı yeniden kullanımı onu atlatabilir.

Detection

Runtime monitor'ları JOP'u, gadget boyutundaki dizilimlere yapılan sık indirect jump'ların ve tekrarlayan bir dispatcher'ın istatistiksel imzasıyla işaretler (örn. JOP-alarm tarzı anomali tespiti), çünkü meşru kod nadiren birçok kısa indirect-jump parçasını arka arkaya dizer.

Mitigation

(Artık risk / onu ne durdurur.) Userspace'te IBT'yi etkinleştir ve enforce et; onu fine-grained forward-edge CFI (FineIBT, Clang CFI) ile eşleştir, böylece dispatcher endbr64 hedeflerini serbestçe chain'leyemez. Shadow stack'ler (Intel CET shadow stack) ROP için gereklidir ama JOP'a karşı tek başlarına yetersizdir.

References