Skip to content

JIT Spray (DEP+ASLR bypass)

Bir just-in-time compiler'ı suistimal ederek attacker'ın seçtiği constant'ları executable page'lere olduğu gibi emit ettir, sonra instruction-ortasına atla; böylece o constant byte'lar bir NOP sled artı shellcode olarak decode olur — bir leak veya ROP chain olmadan DEP/W^X ve ASLR'yi yener (Blazakis, 2010).

Mechanism

Neden çalışır

DEP/W^X data page'lerini non-executable yapar ve ASLR kodun nerede yaşadığını gizler. Bir JIT bu invariant'ların ikisini de attacker için kırar: çalışma zamanında yeni executable kod yazar ve attacker-controlled constant'ları doğrudan o koda gömer.

  • Büyük constant'larla dolu bir scripting ifadesi — var x = 0x3c909090 ^ 0x3c909090 ^ ...;XOR EAX, 0x3c909090 gibi bir x86 instruction zincirine derlenir; her biri executable bir JIT page'ine 90 90 90 3c literal byte'larını emit eder.
  • x86'da instruction alignment yoktur, dolayısıyla böyle bir instruction'ın bir byte içine atlamak constant'ı yeniden yorumlar: 0x90 byte'ları NOP olarak decode olur ve takip eden opcode byte'ı yeni bir instruction başlatır. Attacker, gadget/shellcode byte'larını birçok constant içine paketleyip JIT'lenmiş fonksiyonu birçok kez instantiate ederek, bir NOP-sled-artı-payload'ın kopyalarını geniş, öngörülebilir bir address aralığına spray eder.
  • Spray edilen aralık geniş olduğu ve JIT page'leri kaba alignment'larda kümelendiği için, sabit bir landing adresi güvenilir biçimde spray'in içine iner — dolayısıyla hiçbir info leak'e (ASLR) ve hiçbir RET chain'ine (DEP/ROP) gerek yoktur; kontrol sadece sled boyunca kayar ve constant-encoded payload'a girer.
  • Teknik, Dion Blazakis'in 2010 Interpreter Exploitation: Pointer Inference and JIT Spraying çalışmasında tanıtıldı ve Adobe Flash'taki ActionScript JIT'ine karşı demonstre edildi. Variable-length bir ISA gerektirir: ARM gibi fixed-length, aligned ISA'lara aynı şekilde instruction-ortasına atlanamaz.

Hem DEP'in hem de ASLR'nin dayandığı invariant — attacker bilinen executable kodu bilinen bir adrese yerleştiremez — yanlıştır, çünkü JIT tam olarak bunu talep üzerine yapar.

Walkthrough

1. Payload byte'larını JIT'lenmiş constant'lar içine encode et. Hazırlanmış bir immediate'ın her XOR'u executable page'e dört payload byte'ı yerleştirir:

; source:  x = (0x3c909090 ^ 0x3c909090 ^ 0x3c909090 ^ ...);
; emitted: B8 90 90 90 3C    MOV EAX, 0x3c909090
;          35 90 90 90 3C    XOR EAX, 0x3c909090
;          35 90 90 90 3C    XOR EAX, 0x3c909090

2. off+1'de girerek yeniden yorumla. Baştaki opcode byte'ını atlamak, stream'i her instruction'ın kendi opcode'unu tüketen bir sled'e çevirir:

; entry at offset +1:
90               NOP
90               NOP
90               NOP
3C 35            CMP AL, 0x35     ; harmless, advances to next constant -> sled

3. Birçok kopya spray et. JIT'lenmiş fonksiyonu binlerce kez instantiate et, böylece executable kopyalar öngörülebilir bir aralığı örter, sonra kontrolü bir corruption primitive ile sabit bir instruction-ortası adrese yönlendir:

EIP = 0x0c0c0c0d   ; lands at off+1 inside a sprayed region -> NOP sled -> payload

Beklenen sonuç: yürütme gömülü NOP'lar boyunca kayar ve constant-encoded shellcode'a girer. DEP ve ASLR, hiçbir leak ve hiçbir ROP olmadan bypass edilir.

Constant blinding + W^X JIT ile yenilir

Standart düzeltme constant blinding'dir: büyük immediate'ları emit'ten önce process başına rastgele bir cookie ile XOR'la, böylece attacker'ın gördüğü byte'lar öngörülemez olur; randomize edilmiş/guard'lanmış JIT page yerleşimi, alignment'ı bozmak için rastgele NOP-insertion ve W^X JIT (page'ler ya writable ya executable'dır, asla ikisi birden — kodu yaz, sonra execute'a flip et) ile birleştirilir. İlgili varyantlara bak: asm.js-targeted JIT spray ve constant-embedded gadget JIT spray.

Detection

Birçok büyük-constant yüklü executable page üreten bir JIT compilation patlaması ya da yürütmenin bir JIT page'ine non-entry (instruction-ortası) offset'te girmesi anormaldir — gerçi tasarım gereği input sıradan numerik script gibi görünür.

Mitigation

(Onu ne durdurur.) Constant blinding (immediate'larda byte-smuggling'i yener), W^X / write-xor-execute JIT page'leri, randomize edilmiş JIT region base'i ve guard page'ler ile NX-by-default. Bunlar spray'in iki varsayımına saldırır — öngörülebilir byte'lar ve öngörülebilir bir adres.

References