Skip to content

Data Execution Prevention (DEP)

DEP/NX, data page'lerini (stack, heap) non-executable işaretler; control flow bu page'lerden enjekte edilmiş shellcode'u çalıştırmaya kalkarsa CPU fault üretir — yani W^X'i enforce eder.

Mechanism

Bug class / invariant

DEP, W^X ("write XOR execute") invariant'ını enforce eder: bir page ya writable ya da executable olabilir, ama ikisi birden olamaz. CPU'nun page başına tuttuğu NX/XD bit'i data bölgelerini (stack, heap, code olmayan çoğu mapping) non-executable işaretler. Bozulmuş bir control-flow transfer'i execution'ı böyle bir bölgeye yönlendirirse — klasik "shellcode'u stack/heap'e enjekte et ve oraya jump et" saldırısı — processor bir fault üretir ve OS process'i öldürür. DEP böylece doğrudan code injection'ı etkisiz hale getirir. Tam da bu varlığı, attacker'ları enjekte edilmiş byte'lar yerine mevcut executable code'u çalıştıran code-reuse tekniklerine (ROP/JOP) itmiştir.

Donanım seviyesinde bu, page-table entry'sindeki bir bit'tir; vendor'lar aynı özelliği farklı adlandırır: AMD NX (No-eXecute), Intel XD (eXecute Disable), ARM XN (eXecute Never) ve MIPS XI (eXecute Inhibit). x86-64'te (long mode / PAE paging) bu, page-table entry'sinin en anlamlı bit'i olan bit 63'tür: 0 ise page executable, 1 ise o page'den yapılan instruction fetch'ler fault'lar. Microsoft bunu userspace'e DEP olarak sunar (Windows XP SP2'den beri default), Linux/BSD'ler ise CPU NX sunduğu her yerde eşdeğer non-executable stack/heap mapping'lerini zorunlu kılar.

Walkthrough

Üst seviye, kavramsal (iyi belgelenmiş platform davranışı):

  1. OS, data page'lerini (stack/heap) NX set edilmiş olarak map'ler; yalnızca meşru code section'ları executable'dır.
  2. Bir memory-corruption bug'ı, attacker'ın bir data buffer'a shellcode yazmasına ve instruction pointer'ı ona doğru hijack etmesine izin verir.
  3. CPU bir NX page'ten execute etmeye çalışır.
  4. Bir no-execute fault üretilir; OS process'i sonlandırır — enjekte edilen shellcode asla çalışmaz.
  5. Bypass için attacker'lar code-reuse'a geçer: mevcut executable gadget'ları zincirler (return-oriented programming) ya da bir page'i executable yapmak için ROP üzerinden VirtualProtect/mprotect çağırır (VirtualProtect/mprotect via ROP).

Bir Linux binary'sinin stack'inin NX-protected olup olmadığını GNU_STACK program header'ından kontrol edebilirsin (RWE executable, RW NX-protected demektir):

readelf -l ./vuln | grep -A1 GNU_STACK
Beklenen çıktı (NX-protected stack)

GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
               0x0000000000000000 0x0000000000000000  RW     0x10
RW (RWE değil) flag'i kernel'e stack'i execute permission'ı olmadan map etmesini söyler. gcc -z execstack ile derlenen bir binary RWE gösterir ve eski enjekte-shellcode saldırı yüzeyini yeniden tanıtır.

Warning

DEP tek başına ROP/JOP'u ya da data-only saldırıları durdurmaz. Etkili olması için forward/backward-edge CFI ve ASLR ile birlikte kullanılmalıdır.

Detection

  • Data page'lerinde no-execute / access-violation crash'leri — untrusted-input işleme sırasında tekrarlayan DEP fault'ları code-injection denemelerine işaret eder.
  • WER / Exploit Protection event'leri; DEP-enabled process'lerde EDR crash telemetry'si.
  • Page'leri RX'e çeviren şüpheli runtime VirtualProtect/mprotect çağrıları (yaygın bir DEP-bypass belirtisi), özellikle JIT olmayan process'lerden.

Mitigation

  • DEP/NX'in system-wide ve process başına enabled olduğundan emin ol (modern OS'lerde default'tur; legacy app'ler için opt-out'tan kaçın).
  • ASLR, Control Flow Guard ve CET shadow stacks ile birleştir.
  • RWX mapping'lerini minimize et; executable bellek'in dinamik olarak oluşturulmasını/değiştirilmesini yasaklamak için Arbitrary Code Guard kullan.

References