NX
简介
No-eXecute(NX),表示不可执行,其原理是将数据所在的内存页(例如堆和栈)标识为不可执行,如果程序产生溢出转入执行shellcode时,CPU就会抛出异常。通常我们使用可执行空间保护(executable space protection)作为一个统称,来描述这种防止传统代码注入攻击的技术——攻击者将恶意代码注入正在运行的程序中,然后使用内存损坏漏洞将控制流重定向到该代码。实施这种保护的技术有多种名称,在 Windows上称为数据执行保护(DEP),在Linux上则有 NX、WX、Pax和 Exec Shield 等。
NX的实现需要结合软件和硬件共同完成。首先在硬件层面,它利用处理器的NX位,对相应页表项中的第63位进行设置,设置为1表示内容不可执行,设置为0则表示内容可执行。一旦程序计数器(PC)被放到受保护的页面内,就会触发硬件层面的异常。其次,在软件层面,操作系统需要支持 NX,以便正确配置页表,但有时这会给自修改代码或者动态生成的代码(JT编译代码)带来一些问题,这在浏览器上很常见。这时,软件需要使用适当的API来分配内存,例如Wimdows上使用 VirtualProtect 或 VirtualAlloc,Linux上使用mprotect或者 mmap,这些 API 允许更改已分配页面的保护级别。
在 Linux 中,当装载器将程序装载进内存空间后,将程序的.text节标记为可执行,而其余的数据段(.data、.bss等)以及栈、堆均为不可执行。因此,传统的通过修改GOT来执行shellcode 的方式不再可行。但NX这种保护并不能阻止攻击者通过代码重用来进行攻击(ret2libc)。
如下所示,Ubuntu 中已经默认启用了NX。GNUSTACK段在禁用NX时权限为RWE,而开启
后权限仅为 RW,不可执行。
$ gcc zexecstack hello,c && readelf -l a.out | grep-A1 GNU STACK # 禁用 |
