No-exec / NX
Tip
学习和实践 AWS 黑客技术:
HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
基本信息
The No-Execute (NX) bit, also known as Execute Disable (XD) in Intel terminology, 是一个基于硬件的安全特性,旨在缓解****buffer overflow攻击的影响。启用并正确实现后,它会区分用于可执行代码的内存区域和用于数据的区域,例如 stack 和 heap。核心思想是阻止攻击者通过将恶意代码(例如放在 stack)并将执行流指向它,从而利用 buffer overflow 漏洞来执行恶意代码。
现代操作系统通过支撑 ELF program headers 的页表属性来强制实施 NX。例如,PT_GNU_STACK header 与 GNU_PROPERTY_X86_FEATURE_1_SHSTK 或 GNU_PROPERTY_X86_FEATURE_1_IBT 属性结合,告知 loader stack 应为 RW 还是 RWX。当 NX 启用且二进制使用非可执行 stack 链接(-z noexecstack)时,任何将执行流转入攻击者控制的数据页(stack、heap、mmap’ed buffers 等)的尝试都会产生故障,除非这些页面被显式标记为可执行。
快速检测 NX
checksec --file ./vuln将根据GNU_STACKprogram header 显示NX enabled或NX disabled。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。- 在运行时,
/proc/<pid>/maps会显示某个分配是否为rwx、rw-、r-x等,这对验证 JIT 引擎或自定义分配器很有帮助。
绕过
代码重用原语
可以使用诸如 ROP 来绕过 此保护,通过执行二进制中已存在的可执行代码片段。典型的链包括:
- Ret2libc
- Ret2syscall
- Ret2dlresolve 当二进制没有导入
system/execve时 - Ret2csu 或 Ret2vdso 用于合成 syscalls
- Ret2… — 任何允许你将受控寄存器状态与现有可执行代码拼接以调用 syscalls 或库 gadgets 的调度器。
通常的工作流程是:(1) 通过 info leak 来 leak 代码或 libc 指针,(2) 解析函数基址,和 (3) 构造一个永远不需要攻击者可控可执行字节的链。
Sigreturn Oriented Programming (SROP)
SROP 在可写页上构造一个伪 sigframe,并将执行枢转到 sys_rt_sigreturn(或相关 ABI 的等价项)。内核随后“恢复”该构造的上下文,立即给予对所有通用寄存器、rip 和 eflags 的完全控制。近期的 CTF 挑战(例如 n00bzCTF 2023 中的 Hostel 任务)展示了 SROP 链如何先调用 mprotect 将栈切换为 RWX,然后重用该栈来放置 shellcode,从而在即便只有单个 syscall; ret gadget 可用的情况下也能有效绕过 NX。更多架构相关的技巧请参见专门的 SROP page。
Ret2mprotect / ret2syscall 来翻转权限
如果你能调用 mprotect、pkey_mprotect,甚至 dlopen,你就可以在运行 shellcode 之前合法地请求可执行映射。一个小的 pwntools 骨架如下:
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 区域,执行就可以安全地跳入攻击者控制的字节。
来自 JIT 引擎和内核的 RWX 原语
动态生成代码的 JIT 引擎、解释器、GPU 驱动和内核子系统,通常是在严格 NX 策略下重新获得可执行内存的常见途径。2024 年的 Linux 内核漏洞 CVE-2024-42067 表明 set_memory_rox() 的失败会导致 eBPF JIT 页面同时可写 且 可执行,使攻击者能够在内核中喷洒 gadgets 或整个 shellcode blobs,尽管存在 NX/W^X 的预期。获得对 JIT 编译器(BPF、JavaScript、Lua 等)的控制的利用链因此可以将其载荷放在这些 RWX 区域,并只需一次函数指针覆盖即可跳入。
非返回式代码重用 (JOP/COP)
如果 ret 指令被加固(例如 CET/IBT),或者二进制文件缺乏足够的 ret gadgets,就转向 Jump-Oriented Programming (JOP) 或 Call-Oriented Programming (COP)。这些技术构建使用二进制或已加载库中 jmp [reg] 或 call [reg] 序列的调度器。它们仍然符合 NX,因为复用的是现有的可执行代码,但可以规避那些专门检测大量 ret 链的缓解措施。
参考资料
Tip
学习和实践 AWS 黑客技术:
HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
HackTricks

