No-exec / NX

Tip

AWS Hacking’i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking’i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin

Temel Bilgiler

The No-Execute (NX) bit, also known as Execute Disable (XD) in Intel terminology, is a hardware-based security feature designed to azaltmak the effects of buffer overflow attacks. Uygulandığında ve etkinleştirildiğinde, yürütülebilir kod için ayrılmış bellek bölgeleri ile veri amaçlı olanlar (ör. stack ve heap) arasında ayrım yapar. Temel fikir, saldırganın örneğin kötü amaçlı kodu stack’e koyup yürütmeyi ona yönlendirerek buffer overflow zafiyetinden yararlanmasını engellemektir.

Günümüz işletim sistemleri, ELF program başlıklarını destekleyen sayfa tablosu öznitelikleri aracılığıyla NX’i uygular. Örneğin, PT_GNU_STACK başlığı ile GNU_PROPERTY_X86_FEATURE_1_SHSTK veya GNU_PROPERTY_X86_FEATURE_1_IBT özellikleri bir yükleyiciye stack’in RW mi yoksa RWX mi olması gerektiğini bildirir. NX etkin ve binary non-executable stack ile linklenmişse (-z noexecstack), yürütmeyi saldırgan kontrolündeki veri sayfalarına (stack, heap, mmap’ed buffers, vb.) çevirmeye yönelik her deneme, bu sayfalar açıkça yürütülebilir olarak işaretlenmedikçe bir hata oluşturur.

NX’i hızlıca tespit etme

  • checksec --file ./vuln komutu GNU_STACK program başlığına göre NX enabled veya NX disabled gösterecektir.
  • readelf -W -l ./vuln | grep GNU_STACK stack izinlerini ortaya çıkarır; bir E bayrağının varlığı stack’in yürütülebilir (executable) olduğunu gösterir. Örnek:
$ readelf -W -l ./vuln | grep GNU_STACK
GNU_STACK      0x000000 0x000000 0x000000 0x000000 0x000000 RW  0x10
  • execstack -q ./vuln (from prelink) büyük ikili koleksiyonlarını denetlerken kullanışlıdır çünkü hâlâ yürütülebilir bir stack’e sahip ikililer için X yazar.
  • Çalışma zamanında, /proc/<pid>/maps bir atamanın rwx, rw-, r-x, vb. olup olmadığını gösterir; bu, JIT engine’leri veya custom allocator’ları doğrularken faydalıdır.

Atlatmalar

Kod yeniden kullanım primitifleri

Bu korumayı, ikili içinde zaten bulunan yürütülebilir kod parçacıklarını çalıştırarak atlatmak için ROP gibi teknikler kullanmak mümkündür. Tipik zincirler şunları içerir:

  • Ret2libc
  • Ret2syscall
  • Ret2dlresolve — ikili system/execve’yi import etmiyorsa
  • Ret2csu veya Ret2vdso — syscall’ları sentezlemek için
  • Ret2… — kontrol edilen register durumunu mevcut yürütülebilir kodla birleştirerek syscall’ları veya library gadget’larını çağırmanıza izin veren herhangi bir dispatcher.

İş akışı genellikle: (1) bir code veya libc pointer’ını info leak aracılığıyla leak etmek, (2) fonksiyon tabanlarını çözmek ve (3) saldırgan-kontrollü yürütülebilir byte’lara asla ihtiyaç duymayan bir zincir hazırlamaktır.

Sigreturn Oriented Programming (SROP)

SROP yazılabilir bir sayfada sahte bir sigframe oluşturur ve yürütmeyi sys_rt_sigreturn’a (veya ilgili ABI eşdeğerine) yönlendirir. Kernel daha sonra oluşturulmuş bağlamı “geri yükler” ve tüm genel amaçlı register’lar, rip ve eflags üzerinde anında tam kontrol sağlar. Yakın zamanda CTF görevleri (ör. n00bzCTF 2023’teki Hostel görevi) SROP zincirlerinin önce stack’i RWX’e çevirmek için mprotect’i çağırdığını, sonra aynı stack’i shellcode için yeniden kullandığını gösteriyor; böylece yalnızca tek bir syscall; ret gadget’ı mevcut olsa bile NX etkili şekilde atlanır. Daha mimariye özel hileler için ayrılmış SROP page sayfasına bakın.

Ret2mprotect / ret2syscall ile izinleri değiştirme

Eğer mprotect, pkey_mprotect veya hatta dlopen çağırabiliyorsanız, shellcode çalıştırmadan önce meşru olarak yürütülebilir bir mapping talep edebilirsiniz. Küçük bir pwntools iskeleti şöyle görünür:

from pwn import *
elf = ELF("./vuln")
rop = ROP(elf)
rop.mprotect(elf.bss(), 0x1000, 7)
payload = flat({offset: rop.chain(), offset+len(rop.chain()): asm(shellcraft.sh())})

Aynı fikir ret2syscall zincirleri için de geçerlidir; bunlar rax=__NR_mprotect ayarlar, rdi’yi bir mmap/.bss sayfasına işaret eder, istenen uzunluğu rsi’de saklar ve rdx=7 (PROT_RWX) olarak ayarlar. Bir RWX bölgesi oluştuğunda, yürütme güvenle saldırgan-kontrollü baytlara atlayabilir.

RWX primitives from JIT engines and kernels

JIT engine’ler, interpreter’lar, GPU sürücüleri ve dinamik olarak kod üreten kernel alt sistemleri, sıkı NX politikaları altında bile yürütülebilir belleğe tekrar erişmenin yaygın yollarıdır. 2024 Linux kernel açığı CVE-2024-42067 gösterdi ki set_memory_rox()’taki hatalar eBPF JIT sayfalarını hem yazılabilir hem de yürütülebilir bırakarak, saldırganların NX/W^X beklentilerine rağmen kernel içine gadget’lar veya tüm shellcode blob’ları yerleştirmesine izin veriyordu. Bir JIT derleyicisinin (BPF, JavaScript, Lua, vb.) kontrolünü ele geçiren exploit’ler bu yüzden yüklerinin bu RWX alanlarda bulunmasını sağlayabilir ve içlerine atlamak için yalnızca tek bir function pointer overwrite’a ihtiyaç duyar.

Non-return code reuse (JOP/COP)

Eğer ret talimatları sertleştirilmişse (ör. CET/IBT) veya ikili dosya yeterli ret gadget’ına sahip değilse, Jump-Oriented Programming (JOP) veya Call-Oriented Programming (COP)’a geçin. Bu teknikler, ikili veya yüklenmiş kütüphanelerde bulunan jmp [reg] veya call [reg] dizilerini kullanan dispatcher’lar inşa eder. Yine NX’e uyarlar çünkü mevcut yürütülebilir kodu yeniden kullanırlar, fakat özellikle uzun ret zincirlerini izleyen mitigasyonların etrafından dolaşırlar.

ROP & JOP

Referanslar

Tip

AWS Hacking’i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking’i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin