Skip to content

ret2mprotect

Attacker-controlled bir bölgeyi readable-writable-executable (RWX) yapmak için mprotect çağıran, sonra oraya yerleştirilen shellcode'a atlayan bir ROP chain — baştan executable bir mapping olmadan NX/DEP'i atlatır.

Mechanism

Invariant

NX/DEP W^X'i dayatır: yazılabilir page'ler (stack, heap, BSS) executable değildir, dolayısıyla enjekte edilmiş shellcode doğrudan çalışamaz. Savunmacıların dayandığı invariant, data'yı kontrol eden bir attacker'ın onu code'a çeviremeyeceğidir.

mprotect(addr, len, prot), var olan bir mapping'in korumasını değiştiren meşru bir syscall'dır. Bir attacker instruction pointer'ı zaten kontrol ediyorsa (bir stack overflow / ROP üzerinden), buffer'ını içeren page üzerinde prot = PROT_READ|PROT_WRITE|PROT_EXEC (sayısal değer 7) ayarlamak için mprotect'i meşru şekilde çağırabilir, sonra execution'ı oraya yönlendirebilir. Sınır, W^X'i mekanik olarak ihlal ederek değil, programın kendi page izinlerini gevşetme yeteneğini kendisine karşı kullanarak aşılır. Bu, ret2syscall'ın code-execution muadili ve virtualprotect-mprotect-via-rop'un Linux analoğudur.

Walkthrough

Kavramsal chain (x86-64 System V): üç argümanı yükle, mprotect'i çağır, sonra artık-executable buffer'a dön.

# conceptual, pwntools-style — addresses/offsets are target specific
rop  = b'A'*offset
rop += p64(pop_rdi) + p64(page_addr)   # rdi = page-aligned base of the region
rop += p64(pop_rsi) + p64(0x1000)      # rsi = length
rop += p64(pop_rdx) + p64(0x7)         # rdx = PROT_READ|WRITE|EXEC
rop += p64(mprotect_addr)              # call mprotect(page, len, 7)
rop += p64(shellcode_addr)             # return into shellcode in the RWX region

Yaygın varyasyonlar:

  • Syscall formu (libc symbol yok): rax = 10 (x86-64 __NR_mprotect) / eax = 0x7d (i386) ayarla, arg register'larını ayarla ve bir syscall/int 0x80 gadget'ı kullan — ret2syscall ile örtüşür.
  • mprotect + read: bölgeyi RWX yap, sonra izinleri gevşettikten sonra shellcode hazırlamak için read(0, region, n), sabit bir shellcode adresinden kaçınarak.
  • rdx kıtlığı üçüncü argümanı ayarlamak için sık sık ret2csu'yu (ya da onun 2.34+ ardılını) zorlar.
Layout notları

addr page-aligned olmalıdır (düşük 12 bit'i maskeleyerek temizle). Asıl shellcode'dan önce bir NOP sled, jump target'taki belirsizliği tolere eder. PIE/ASLR ile page_addr, mprotect ve gadget adreslerinin hepsi önceden bir leak gerektirir.

Modern engeller

seccomp filter'ları sık sık mprotect'i bloklar (ya da bir page'i hem yazılabilir hem executable yapmayı bloklar) ve bu tekniği etkisizleştirir. Intel CET shadow stack ROP return'lerini kırar; W^X-only kernel'ler ve MDWE/PROT_MAX yeniden-izinlendirmeyi daha da kısıtlar.

Detection

  • Yazılabilir olan bir bölgede — özellikle stack ya da heap'te — PROT_EXEC ayarlayan bir mprotect/mmap call'ı yüksek doğrulukta bir sinyaldir; EDR/auditd/ptrace syscall monitor'ları mprotect(..., PROT_READ|PROT_WRITE|PROT_EXEC)'i işaretleyebilir.
  • Execution'ın, aynı control flow içinde yeni yeniden-izinlendirilmiş (W->X geçişi) bir page'e transfer olması.
  • Stack canary'ler / ASan tarafından yakalanan altta yatan overflow.

Mitigation

  • mprotect'i PROT_EXEC ile ya da aynı anda W+X'i yasaklayan seccomp-bpf allowlist'leri.
  • writable->executable geçişlerini engelleyen Kernel W^X / MDWE (PR_SET_MDWE, MAP_FIXED hardening).
  • ROP chain'i kırmak için Intel CET shadow stack / IBT ve CFI.
  • Chain'in bir leak gerektirmesi için PIE + ASLR + Full RELRO; info leak'lerden kaçın.

References

Ayrıca bkz: ret2syscall, virtualprotect-mprotect-via-rop, ret2csu, return-oriented-programming.