PWN-栈保护机制

一、CANARY(栈溢出保护)

栈溢出保护是一种缓解缓冲区溢出攻击的手段。当函数存在缓冲区溢出攻击漏洞时,攻击者可以通过覆盖栈上的返回地址来让shellcode能够执行。当启用栈保护后,函数开始执行的时候会往栈中插入cookie信息,当函数真正返回时验证cookie信息是否合法,如果不合法就会停止程序运行,从而防止攻击者覆盖返回地址的行为。攻击者在覆盖返回地址的时候往往也会讲cookie信息覆盖掉,导致栈保护检查失败,所以会终止程序来阻止shellcode的执行,在Linux中将cookie信息称为canary。开启栈溢出保护时,虽然不能覆盖canary信息,但是可以对canary的前面进行溢出。

GCC编译时的用法:

1
2
3
4
5
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 //启用堆栈保护,为所有函数插入保护代码
-fno-stack-protector /-fstack-protector / -fstack-protector-all (关闭 / 开启 / 全开启)

二、FORTIFY

fortify可以用于检查缓冲区溢出、格式化字符串等类型的漏洞。适用于程序采用大量字符串或者内存操作的函数

比如:

memcpy

[https://baike.baidu.com/item/memcpy/659918?fr=aladdin]:

memset

[https://baike.baidu.com/item/memset?fromModule=lemma_search-box]:

strcpy

[https://baike.baidu.com/item/strcpy?fromModule=lemma_search-box]:

stpcpy

[https://baike.baidu.com/item/stpcpy?fromModule=lemma_search-box]:

strncpy

[https://baike.baidu.com/item/strncpy?fromModule=lemma_search-box]:

strcat

[https://baike.baidu.com/item/strcat?fromModule=lemma_search-box]:

strncat

[https://baike.baidu.com/item/strncat?fromModule=lemma_search-box]:

sprintf

[https://baike.baidu.com/item/sprintf?fromModule=lemma_search-box]:

snprintf

[https://baike.baidu.com/item/snprintf%28%29?fromtitle=snprintf&fromid=7320492&fromModule=lemma_search-box]:

vsprintf

[https://baike.baidu.com/item/vsprintf?fromModule=lemma_search-box]:

vsnprintf

[https://baike.baidu.com/item/_vsnprintf/5395011?fromModule=search-result_lemma-recommend]:

gets

[https://baike.baidu.com/item/gets?fromModule=lemma_search-box]:

GCC编译时的用法:

1
2
gcc -D_FORTIFY_SOURCE=1  //仅仅只在编译时进行检查(尤其是#include<string.h>这种头文件
gcc -D_FORTIFY_SOURCE=2 //程序执行时也会进行检查(如果检查到缓冲区溢出,就会终止程序)

程序执行时检查是对数组大小进行判断替换strcpy、memcpy、memset等函数名,从而达到防止缓冲区溢出的作用

三、NX(DEP)

NX即No-eXecute(不可执行)的意思,NX(DEP)是一种内存保护技术,它的基本原理是将数据所在内存页标识为不可执行,当程序成功溢出转入shellcode时,程序会尝试在数据页面执行命令,此时CPU就会抛出异常,而不去执行恶意指令,主要防止在数据区溢出。

GCC用法:

1
2
3
4
5
gcc -o test test.c // 默认情况下,开启NX保护
gcc -z execstack -o test test.c // 禁用NX保护
gcc -z noexecstack -o test test.c // 开启NX保护
-z execstack / -z noexecstack (关闭 / 开启)

NX(DEP)保护机制会阻止程序在数据页面上执行指令,从而防止攻击者通过执行恶意代码来获得shell

四、PIE(ASLR)

ASLR(地址空间分布随机化)是一种内存保护技术,它通过随机化程序在内存中的位置来防止缓冲区溢出攻击。一般情况下会和NX(windows平台称为DEP)同时工作。

分为三种情况

1
2
3
0 - 表示关闭进程地址随机化
1 - 表示将mmap的基地址,栈基址和.so地址随机化
2 - 表示在1的基础上增加heap的地址随机化

当ASLR设置为2时,操作系统不仅会随机化栈和库的地址,还会随机化堆的地址,从而增强系统的安全性。

可以防止Ret2lic方式(Ret2libc攻击是攻击者用来绕过DEP(数据执行防护)保护的一种技术。在Ret2libc攻击中,攻击者将程序流重定向到C标准库中的函数)针对DEP的攻击。ALSR和DEP的配合使用,能有效阻止攻击者在堆栈上运行恶意代码

Linux下关闭PIE的命令:

1
sudo -s echo 0 > /proc/sys/kernel/randomize_va_space

GCC编译时用法:

1
2
3
4
5
6
7
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
-no-pie / -pie (关闭 / 开启)

五、RELRO

在Linux系统安全领域数据可以写的存储区就会是攻击的目标,尤其是存储函数指针的区域。所以在安全防护的角度应尽量减少可写的存储区域。

RELRO有两种模式:部分和完整。部分RELRO是GCC的默认设置,几乎所有的二进制文件都至少具有部分RELRO。完整的RELRO使整个全局偏移表(GOT)只读,从而消除了执行“GOT覆盖”攻击的能力 。

GCC用法:

1
2
3
4
5
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 // 全部开启
-z norelro / -z lazy / -z now (关闭 / 部分开启 / 完全开启)