No-exec / NX
Tip
Ucz się i ćwicz Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.
Podstawowe informacje
The No-Execute (NX) bit, also known as Execute Disable (XD) in Intel terminology, is a hardware-based security feature designed to mitigate the effects of buffer overflow attacks. When implemented and enabled, it distinguishes between memory regions that are intended for executable code and those meant for data, such as the stack and heap. The core idea is to prevent an attacker from executing malicious code through buffer overflow vulnerabilities by putting the malicious code in the stack for example and directing the execution flow to it.
Nowoczesne systemy operacyjne egzekwują NX za pomocą atrybutów tabeli stron powiązanych z nagłówkami programu ELF. Na przykład nagłówek PT_GNU_STACK w połączeniu z właściwościami GNU_PROPERTY_X86_FEATURE_1_SHSTK lub GNU_PROPERTY_X86_FEATURE_1_IBT informuje loader, czy stack powinien być RW czy RWX. Gdy NX jest włączony, a binarka została zlinkowana z non-executable stack (-z noexecstack), każda próba przekierowania wykonania na strony danych kontrolowanych przez atakującego (stack, heap, mmap’ed buffers, itd.) spowoduje błąd, chyba że strony te zostały jawnie oznaczone jako wykonywalne.
Szybkie wykrywanie NX
checksec --file ./vulnwill displayNX enabledorNX disabledbased on theGNU_STACKprogram header.readelf -W -l ./vuln | grep GNU_STACKexposes the stack permissions; the presence of anEflag indicates that the stack is executable. Example:
$ readelf -W -l ./vuln | grep GNU_STACK
GNU_STACK 0x000000 0x000000 0x000000 0x000000 0x000000 RW 0x10
execstack -q ./vuln(fromprelink) jest przydatne przy audycie dużych zbiorów binarek, ponieważ wypisujeXdla binarek, które wciąż mają wykonalny stos.- W czasie wykonywania
/proc/<pid>/mapspokaże, czy przydział marwx,rw-,r-xitd., co jest przydatne przy weryfikacji JIT engines lub custom allocators.
Obejścia
Code-reuse primitives
Możliwe jest użycie technik takich jak ROP aby obejść tę ochronę poprzez wykonanie fragmentów wykonalnego kodu już obecnych w binarce. Typowe łańcuchy obejmują:
- Ret2libc
- Ret2syscall
- Ret2dlresolve — gdy binarka nie importuje
system/execve - Ret2csu lub Ret2vdso — do syntezy syscalls
- Ret2… — każdy dispatcher, który pozwala poskładać kontrolowany stan rejestrów z istniejącym wykonalnym kodem, aby wywołać syscalls lub library gadgets.
Przebieg zwykle wygląda tak: (1) leak wskaźnika do kodu lub libc przez info leak, (2) rozwiązać bazy funkcji, oraz (3) stworzyć łańcuch, który nigdy nie potrzebuje wykonawczych bajtów kontrolowanych przez atakującego.
Sigreturn Oriented Programming (SROP)
SROP buduje fałszywy sigframe na zapisywalnej stronie i pivotuje wykonanie na sys_rt_sigreturn (lub odpowiednik ABI). Kernel następnie „przywraca” spreparowany kontekst, natychmiast dając pełną kontrolę nad wszystkimi rejestrami ogólnego przeznaczenia, rip i eflags. Najnowsze zadania CTF (np. zadanie Hostel w n00bzCTF 2023) pokazują, jak łańcuchy SROP najpierw wywołują mprotect, aby zmienić stos na RWX, a następnie ponownie używają tego samego stosu do shellcode, efektywnie omijając NX nawet gdy dostępny jest tylko pojedynczy gadget syscall; ret. Sprawdź dedykowaną SROP page po więcej trików specyficznych dla architektury.
Ret2mprotect / ret2syscall to flip permissions
If you can call mprotect, pkey_mprotect, or even dlopen, you can legitimately request an executable mapping before running shellcode. A small pwntools skeleton looks like:
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())})
Ta sama idea ma zastosowanie do łańcuchów ret2syscall, które ustawiają rax=__NR_mprotect, wskazują rdi na stronę mmap/.bss, zapisują żądaną długość w rsi i ustawiają rdx=7 (PROT_RWX). Gdy istnieje region RWX, wykonanie może bezpiecznie skoczyć do bajtów kontrolowanych przez atakującego.
Prymitywy RWX z silników JIT i jądra
Silniki JIT, interpretery, sterowniki GPU i podsystemy jądra, które dynamicznie emitują kod, są powszechnym sposobem na odzyskanie pamięci wykonalnej nawet przy restrykcyjnej polityce NX. Wada jądra Linux z 2024 r. CVE-2024-42067 wykazała, że błędy w set_memory_rox() pozostawiały strony eBPF JIT zapisywalne i wykonywalne, pozwalając atakującym umieścić gadgety lub całe shellcode blobs wewnątrz jądra pomimo oczekiwań NX/W^X. Eksploity, które przejmą kontrolę nad kompilatorem JIT (BPF, JavaScript, Lua itd.), mogą więc umieścić swój payload w tych obszarach RWX i potrzebują tylko jednego function pointer overwrite, aby w nie skoczyć.
Reużycie kodu bez powrotu (JOP/COP)
Jeśli instrukcje ret są wzmocnione (np. CET/IBT) lub binarka nie zawiera bogatych ret gadgetów, przejdź do Jump-Oriented Programming (JOP) lub Call-Oriented Programming (COP). Techniki te budują dyspozytory wykorzystujące sekwencje jmp [reg] lub call [reg] znalezione w binarce lub załadowanych bibliotekach. Nadal respektują NX, ponieważ ponownie używają istniejącego wykonalnego kodu, ale omijają środki łagodzące, które specyficznie monitorują długie łańcuchy instrukcji ret.
Referencje
Tip
Ucz się i ćwicz Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.
HackTricks

