linux安全机制

Stack Canaries

  Stack Canaries(取名自地下煤矿的金丝雀,因为它能比矿工更早地发现煤气泄漏,有预警的作用)是一种用于对抗栈溢出攻击的技术,即ssp安全机制,有时也叫做Stack cookies。Canary的值是栈上的一个随机数,在程序启动时随机生成并保存在比函数返回地址更低的位置。由于栈溢出是从低地址向高地址进行覆盖,因此攻击者要想控制函数的返回指针,就一定要先覆盖到Canary。程序只需要在函数返回前检查Canary是否被篡改,就可以达到保护栈的目的。

 

 

No-eXecute

  No-eXecute(NX),表示不可执行,其原理是将数据所在的内存页(例如栈和堆)标识为不可执行,如果程序产生溢出转入执行shellcode时,CPU就会抛出异常。通常我们使用可执行空间保护(executable space protection)作为一个统称,来描述这种防止传统代码注入攻击的技术———攻击者将恶意代码注入正在运行的程序中,然后使用内存损坏漏洞将控制流重定向到该代码。实施这种保护的技术有多种名称,在windows上称为数据执行保护(DEP),在Linux上有NX、W^X、PaX和Exec Shield等。

 

 

ASLR

  大多数攻击都基于这样一个前提,即攻击者知道程序的内部布局。因此,引入内存布局的随机化能有效增加漏洞利用的难度,其中一种技术就是地址空间布局随机化(Address Space Layout Randomization,ASLR)它最早出现于2001年出现在PaX项目中,于2005年正式成为Linux的一部分,如今已经广泛使用在各类操作系统中。ASLR提供的只是概率上的安全性,根据用于随机化的熵,攻击者有可能幸运地猜测到正确的地址,有时攻击者还可以爆破。一个著名的例子是Apache服务器,它的每个连接都会复刻一个子进程,但这些子进程并不会重新进行随机化,而是与主进程共享内存布局,所以攻击者可以不断尝试,直到找到正确地址。

PIE

  由于ASLR是一种操作系统层面的技术,而二进制程序本身是不支持随机化加载的,便出现了一些绕过的方式,例如ret2plt、GOT劫持、地址爆破。于是人们于2003年引入了位置无关可执行文件(Position-Independent Executable,PIE),它在应用层的编译器上实现,通过将程序编译为位置无关代码(Position-Independent Code,PIC),使程序可以加载到任意位置,就像一个特殊的共享库。在PIE和ASLR同时开启的情况下,攻击者将对程序内部布局一无所知,大大增加了利用难度。当然凡事有利有弊,在增加安全性的同时,PIE也会一定程度的影响性能,因此在大多数操作系统上PIE仅用于一些对安全性要求比较高的程序

FORTIFY_SOURCE

      我们知道缓冲区溢出常常发生在程序调用了一些危险函数的时候,例如操作字符串的函数memcpy(),当源字符串的长度大于目的缓冲区的长度时,就会发生缓冲区溢出。这时就需要一种针对危险函数的检查机制,在编译时尝试去确定风险是否存在,或者将危险函数替换为相对安全的函数实现,以大大降低缓冲区溢出发生的风险。

  FORTIFY_SOURCE就是这样的一个检查机制它最初来自2004年RedHat工程师针对GCC和glibc的一个安全补丁,该补丁为字符串操作函数提供了轻量级的缓冲区溢出攻击和格式化字符串攻击检查,它会将危险函数替换成安全函数,且不会对程序执行的性能产生大的影响。目前所支持的函数有memcpy,memmove、memset、strcpy、stpcpy、strncpy、strncat、sprintf、vsprintf、snprintf、vsnprintf、gets等,这些安全函数位于glibc源码的debug下。

  在Ubuntu16.04(GCC-5.4.0)上,该机制是默认关闭的。当指定优化等级(-O)为1以上,相当于默认开启FORTIFY_SOURCE的等级为1,如果我们希望检查等级为2,则需要手动指定参数。当然该机制并不仅仅能够用于glibc,只需要将相应的头文件string.h、stdio.h等打上补丁,也能够获得该机制保护。

    -D_FORTIFY_SOURCE=1时,开启缓冲区溢出攻击检查;

    -D_FORTIFY_SOURCE=2时,开启缓冲区溢出以及格式化字符串攻击检查。

 

RELRO

  在启用延迟绑定时,符号的解析只发生在第一次使用的时候,该过程是通过PLT表进行的,解析完成后,相应的GOT条目会被修改为正确的函数地址。因此,在延迟绑定的情况下,.got.plt必须是可写的,这就给了攻击者篡改地址劫持程序的可能。

  RELRO(ReLocation Read-Only)机制的提出就是为了解决延迟绑定的安全问题,它最初于2004年由Redhat工程师Jakub Jlinek实现,他将符号重定向表设置为只读,或者在程序启动时就绑定所有动态符号,从而避免GOT上的地址被篡改。如今,RELOR有两种形式:

    Partial RELRO:一些段(包括.dynamic、.got等)在初始化后将会被标记为只读。在Ubuntu16.04(GCC-5.4.0)上,默认开启Partial RELRO

    Full RELRO:除了Partial RELRO,延迟绑定被禁止,所有人的导入符号将在开始时被解析,.got.plt段会被完全初始化为目标函数的最终地址,并被mprotect标记为只读,但其实.got.plt会直接被合并到.got,也就看不到这段了。另外link_map和_dl_runtime_resolve的地址也不会被装入。开启Full RELRO会对程序启动时的性能造成一定的影响,但也只有这样才能防止攻击者篡改GOT。

 

posted @ 2021-09-07 22:00  丹青初鸿  阅读(790)  评论(0编辑  收藏  举报