No-exec / NX
Tip
Вивчайте та практикуйте AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
Основна інформація
Біт No-Execute (NX), також відомий як Execute Disable (XD) в термінології Intel, — це апаратна функція безпеки, призначена для пом’якшити наслідків атак типу buffer overflow. При реалізації та ввімкненні він розрізняє області пам’яті, призначені для executable code, і ті, що призначені для data, такі як stack і heap. Головна ідея — перешкодити атакувальнику виконати шкідливий код через вразливості buffer overflow, наприклад розмістивши шкідливий код у stack і спрямувавши туди потік виконання.
Сучасні операційні системи примусово застосовують NX через атрибути page table, що підтримують заголовки ELF. Наприклад, заголовок PT_GNU_STACK у поєднанні з властивостями GNU_PROPERTY_X86_FEATURE_1_SHSTK або GNU_PROPERTY_X86_FEATURE_1_IBT повідомляє loader, чи має stack бути RW чи RWX. Коли NX увімкнено і бінарник зібрано з невиконуваним стеком (-z noexecstack), будь-яка спроба перенаправити виконання в керовані атакувальником сторінки даних (stack, heap, mmap’ed buffers тощо) призведе до помилки, якщо ці сторінки явно не були позначені як виконувані.
Швидке виявлення NX
checksec --file ./vulnпокажеNX enabledабоNX disabledна основі заголовкаGNU_STACK.readelf -W -l ./vuln | grep GNU_STACKпоказує дозволи для stack; наявність прапораEвказує, що stack є виконуваним. Приклад:
$ readelf -W -l ./vuln | grep GNU_STACK
GNU_STACK 0x000000 0x000000 0x000000 0x000000 0x000000 RW 0x10
execstack -q ./vuln(fromprelink) зручно при перевірці великих колекцій бінарників, оскільки він виводитьXдля бінарників, що все ще мають executable stack.- Під час виконання
/proc/<pid>/mapsпокаже, чи виділення єrwx,rw-,r-xтощо, що корисно при перевірці JIT engines або custom allocators.
Обходи
Code-reuse primitives
Можна використати техніки на кшталт ROP для обходу цього захисту шляхом виконання шматків executable code, які вже присутні в бінарнику. Типові ланцюжки включають:
- Ret2libc
- Ret2syscall
- Ret2dlresolve коли бінарник не імпортує
system/execve - Ret2csu або Ret2vdso для синтезу syscalls
- Ret2… — будь-який диспетчер, що дозволяє зшивати контрольований стан регістрів з наявним executable code для виклику syscalls або library gadgets.
Зазвичай робочий процес такий: (1) leak code або libc pointer через info leak, (2) визначити bases функцій, та (3) скласти chain, який ніколи не потребує attacker-controlled executable bytes.
Sigreturn Oriented Programming (SROP)
SROP будує фейковий sigframe на writable сторінці і переносить виконання до sys_rt_sigreturn (або відповідного ABI еквівалента). Kernel потім «відновлює» зконструйований контекст, миттєво надаючи повний контроль над усіма general-purpose registers, rip та eflags. Недавні CTF задачі (наприклад, завдання Hostel у n00bzCTF 2023) показують, як SROP-ланцюжки спочатку викликають mprotect, щоб переключити стек у RWX, а потім повторно використовують той самий стек для shellcode, ефективно обходячи NX навіть коли доступний лише один syscall; ret gadget. Див. присвячену SROP page для більш архітектурно-специфічних трюків.
Ret2mprotect / ret2syscall to flip permissions
Якщо ви можете викликати mprotect, pkey_mprotect або навіть dlopen, ви можете легітимно запросити executable mapping перед запуском shellcode. Маленький pwntools skeleton виглядає так:
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())})
Та сама ідея застосовується до ланцюгів ret2syscall, які встановлюють rax=__NR_mprotect, вказують rdi на сторінку mmap/.bss, записують бажану довжину в rsi і встановлюють rdx=7 (PROT_RWX). Як тільки існує RWX-область, виконання може безпечно стрибнути в байти, контрольовані атакуючим.
RWX-примітиви з JIT-двигунів та ядер
JIT-двигуни, інтерпретатори, драйвери GPU та підсистеми ядра, які динамічно генерують код, є поширеним способом відновити виконувану пам’ять навіть при суворих NX-політиках. Уразливість ядра Linux 2024 року CVE-2024-42067 показала, що збої в set_memory_rox() залишали сторінки eBPF JIT одночасно записуваними і виконуваними, дозволяючи атакуючим розпилювати gadgets або цілі shellcode blobs всередині ядра, незважаючи на очікування NX/W^X. Експлойти, які отримують контроль над JIT-компілятором (BPF, JavaScript, Lua тощо), можуть помістити свій payload у ці RWX-області й потребують лише одного перезапису вказівника на функцію, щоб стрибнути в них.
Повторне використання коду без return (JOP/COP)
Якщо інструкції ret захищені (наприклад, CET/IBT) або в бінарі бракує виразних ret gadgets, переходьте до Jump-Oriented Programming (JOP) або Call-Oriented Programming (COP). Ці техніки будують диспетчери, які використовують послідовності jmp [reg] або call [reg], знайдені в бінарному файлі або завантажених бібліотеках. Вони все ще дотримуються NX, оскільки повторно використовують існуючий виконуваний код, але обходять заходи пом’якшення, що спеціально відстежують великі ланцюги інструкцій ret.
Посилання
Tip
Вивчайте та практикуйте AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.


