简介
操作系统提供了许多安全机制来尝试降低或阻止缓冲区溢出攻击带来的安全风险。例如 NX/DEP、 ASLR(PIE)、CANARY、FORTIFY、RELRO 等手段。
栈保护
1.NX/DEP
Linux 和 Windows 平台都支持对非可执行代码的保护,在 Linux 平台中被称为 NX (No-eXecute protect) ,在 Windows 中叫做 DEP (Data Execution Prevention) 。
其基本原理是将数据所在内存页标识为不可执行,当程序溢出成功转入 ShellCode 时,程序会尝试在数据页面上执行指令,此时 CPU 就会抛出异常,而不是去执行恶意指令。
GCC 编译器默认开启了 NX 选项,可以通过添加 -z execstack
编译参数关闭 NX 选项。
-z execstack //关闭
-z noexecstack //开启
2. Canary
当启用栈保护后,函数开始执行的时候会先往栈里插入 Cookie 信息,函数返回时会验证 Cookie 信息是否合法,非法则停止运行。
攻击者在覆盖返回地址的时候往往也会将 Cookie 信息给覆盖掉,导致栈保护检查失败进而阻止 ShellCode 的执行,在 Linux 中将 Cookie 信息称为 Canary 。
GCC 在 4.2 版本中添加了 -fstack-protector
和 -fstack-protector-all
编译参数以支持栈保护功能,4.9 新增了 -fstack-protector-strong
编译参数让保护的范围更广,在编译时可以配置控制是否开启栈保护以及程度。
-fstack-protector //启用保护,不过只为局部变量中含有数组的函数插入保护
-fstack-protector-all //启用保护,为所有函数插入保护
-fstack-protector-strong //针对gcc4.9以后版本,为所有函数插入保护
-fstack-protector-explicit //只对有明确stack_protect attribute的函数开启保护
-fno-stack-protector //禁用保护.
3. ASLR
Address Space Layout Randomization, ASLR 地址空间布局随机化,该技术在 2005 年的 Kernel 2.6.12 版本中引入,会将进程的某些内存空间地址进行随机化来增大入侵者预测目的地址的难度,从而降低进程被成功入侵的风险。
一般情况下NX和地址空间分布随机化(ASLR)会同时工作。因为 Linux 中堆空间可以通过 mmap()
以及 brk()
这两个系统调用完成的,而在不同的等级上面可能会只有部分接口被随机化。如果当前 ASLR 等级为 1,那么当申请空间大于 128K 时,系统通过 mmap()
分配空间,得到的地址是随机的;而当申请空间小于 128K 时,系统是通过 brk()
进行分配的,得到的地址是静止的.
GCC编译器修改:
-fno-pie -no-pie //关闭
-fpie -pie //可执行等级1
-fPIE -pie //可执行等级2
-fpic //共享库等级1
-fPIC //共享库等级2
Linux运行修改:
# sysctl -n kernel.randomize_va_space
cat /proc/sys/kernel/randomize_va_space
# sysctl -w kernel.randomize_va_space=0
echo 2 > /proc/sys/kernel/randomize_va_space
4. FORTIFY
用于检查是否存在缓冲区溢出的错误,针对的是字符串、内存操作函数,例如 memcpy memset strcpy strcats snprintf 等等。
可以通过 _FORTIFY_SOURCE
宏定义检查的级别:
_FORTIFY_SOURCE=1
仅在编译时检查。_FORTIFY_SOURCE=2
在程序运行时也会检查,如果判断到缓冲区溢出则会直接终止程序。
实际上 GCC 会到生成了一些附加代码,通过对数组大小的大小进行判断,从而达到防止缓冲区溢出的作用
-D_FORTIFY_SOURCE=1 //较弱检查
-D_FORTIFY_SOURCE=1 //较强检查
5. RELRO
在 Linux 系统安全领域,数据可写的存储区就会是攻击的目标,尤其是存储函数指针的区域,所以在安全防护的角度来说尽量减少可写的存储区域对安全会有极大的好处。
GCC 提供了一种 Read Only Relocation 的方法,其原理为是由 linker 指定 binary 的一块经过 dynamic linker 处理过 relocation 之后的区域为只读.
设置符号重定向表格为只读或在程序启动时就解析并绑定所有动态符号,从而减少对 Global Offset Table, GOT 攻击。
norelro // 关闭
lazy // 部分开启 即Partial RELRO
now // 全部开启
6.其他
动态路径搜索:可以通过 -Wl,--disable-new-dtags
表明使用 RPATH
;通过 -Wl,--enable-new-dtags
标示使用 RUNPATH
checksec: 是一个 Bash 脚本,可以用来检查可执行文件属性,例如 PIE
RELRO PaX Canaries, ASLR, Fortify Source等等属性。
详细可以查看官网 TrapKit CheckSec 或者 Github CheckSec ,也可以直接使用 本地保存 。