-
-
[原创Linux程序保护机制
-
发表于: 2024-7-9 08:06 3242
-
Linux保护机制
1.Stack Canaries
Stack Canaries是一种用于对抗栈溢出攻击的技术,即SSP安全机制,有时也叫作Stack cookies。Canayr的值是栈上的一个随机数,在程序启动时随机生成并保存在比函数返回地址更低的位置(即更低的地址)。由于栈溢出是从低地址向高地址进行覆盖,因此攻击者要想控制函数的返回指针,就一定要先覆盖到Canary。程序只需要在函数返回前检查Canary是否杯篡改,就可以达到保护栈的目的。
- 栈溢出通常可以分为3类:terminator、random和random XOR,具体的实现有StackGuard、StackShield、ProPoliced等。
- Terminator canaires:由于许多栈溢出都是由于字符串操作不当所产生的,而这些字符串以NULL"\x00"结尾,换个角度看也就是会被"\x00"所截断。基于这一点,terminator canaires讲低位设置为"\x00",即可以防止被泄露,也可以防止被伪造。截断字符还包括CR(0x0d)、LF(0x0a)和EOF(0xff)
- Random canaires:为防止canaries被攻击者猜到,random canaires通常在程序初始化时随机生成,并保存在一个相对安全的地方。当然如果攻击者知道它的位置,还是有可能被读出来。随机数通常由/dev/urandom生成,有时也用当前时间的哈希。
- Random XOR canaires:与random canaires类似,但多了一个XOR操作,这样无论是canaires被篡改还是与之XOR的控制数据被篡改,都会发生错误,这就增加了攻击难度。
1 2 3 4 | gcc -o test test .c // 默认情况下,不开启Canary保护 gcc -fno-stack-protector -o test test .c // 禁用栈保护 gcc -fstack-protector -o test test .c // 启用堆栈保护,不过只为局部变量中含有 char 数组的函数插入保护代码 gcc -fstack-protector-all -o test test .c // 启用堆栈保护,为所有函数插入保护代码 |
2.No-eXecute
No-eXecuit(NX),表示不可执行,其原理是讲数据所在的内存页(例如堆和栈)标识为不可执行,如果程序产生溢出转入执行shellcode时,CPU就会抛出异常。通常我们使用可执行空间保护作为一个统称,来描述这种防止传统代码注入攻击的技术——攻击者讲恶意代码注入正在运行的程序中,然后使用内存损坏漏洞讲控制流重定向到该代码。
NX的实现需要结合软件和硬件共同完成。首先在硬件层面,它利用处理器的NX位,对相应页表项中的第63位进行设置,设置为1表示内容不可执行,设置为0则表示内容可执行。一旦程序程序计数器被放到受保护的页面内,就会触发硬件层面的异常。其次,在软件层面,操作系统需要支持NX,以便正确配置页表,但有时这会给自修改代码或者动态生成的代码代理一些问题,则在浏览器上很常见。
脚本checksec对NX的检测也是基于GNU_STACK段的权限来进行判断的。
1 2 3 | gcc -o test test .c // 默认情况下,开启NX保护 gcc -z execstack -o test test .c // 禁用NX保护 gcc -z noexecstack -o test test .c // 开启NX保护 |
3.ASLR和PIE
3.1 ASLR
大多数攻击都基于这样一个前提,即攻击者知道程序的内存布局。因此,引入内存布局的随机化能够有效增加漏洞利用的难度,其中一种技术就是地址空间布局随机化(ASLR)。ASLP提供的知识概率上的随机安全性,根据用于随机化的墒,攻击者有可能幸运地猜测到正确地址,有时攻击者还可以爆破。
在Linux上,ASLP的全局配置/proc/sys/kernel/randomize_va_space有三种情况:0表示关闭ASLP;1表示部分开启(讲mmap的基址,stack和vdso页面随机化);2表示完全开启(在部分开启的基础上增加heap的随机化)。
1 2 3 | 0 关闭 1 半随机 code&data、stack、mmap、vdso随机化 2 全随机 在 1 的基础上加上heap随机化 |
3.2 PIE
由于ASLP是一种基于操作系统层面的技术,而二进制程序本身是不支持随机化加载的,便出现了一些绕过方式,例如ret2plt、GOT劫持、地址爆破等。于是人们于2003年引入了位置无关可执行文件(PIE),它在应用层的编译器上实现,通过讲程序编译为位置无关代码(PIC),使程序可以被加载到任意位置,就像是一个特殊的共享库。在PIE和ASLR同时开启的情况下,攻击者将对程序的内存布局一无所知,大大增加了利用难度。当然有利也有弊,PIE也会一定程度上影响性能,因此在大多数操作系统上PIE仅用于对安全性要求比较高的程序。
当然,无论是ASLP还是PIE,由于粒度问题,被随机化的都只是某个对象的起始地址,而在该对象的内部依然保持原来的结构,也即是说相对偏移是不会变的。
1 2 3 4 5 | gcc -o test test .c // 默认情况下,不开启PIE gcc -fpie -pie -o test test .c // 开启PIE,此时强度为1 gcc -fPIE -pie -o test test .c // 开启PIE,此时为最高强度2 gcc -fpic -o test test .c // 开启PIC,此时强度为1,不会开启PIE gcc -fPIC -o test test .c // 开启PIC,此时为最高强度2,不会开启PIE |
4.FORTIFY_SOURCE
我们知道缓冲区溢出常常发生在程序调用了一些危险函数的时候,例如操作字符串的函数memcpy(),当源字符串的长度大于目的缓冲区的长度时,就会发生缓冲区溢出。这时需要一种针对危险函数的检查机制,在编译时尝试去确定风险是否存在,或者将危险函数替换为相对安全的函数实现,以大大降低缓冲区溢出发生的风险。
FORTIFY_SOURCE就是这样一个检查机制,它最初来自2004年工程师针对GCC和glibc的一个安全补丁,该补丁为字符串操作函数提供了轻量级的缓冲区溢出攻击和格式化字符串攻击检查,它会将危险函数替换为安全函数,且不会对程序执行的性能产生大的影响。
1 2 3 | gcc -o test test .c // 默认情况下,不会开这个检查 gcc -D_FORTIFY_SOURCE=1 -o test test .c // 较弱的检查 gcc -D_FORTIFY_SOURCE=2 -o test test .c // 较强的检查 |
5.RELRO
1 2 3 4 | gcc -o test test .c // 默认情况下,是Partial RELRO gcc -z norelro -o test test .c // 关闭,即No RELRO gcc -z lazy -o test test .c // 部分开启,即Partial RELRO gcc -z now -o test test .c // 全部开启,即 |
FULLL RELRO(全部开启)
在程序开始之前就进行重定位
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法