漏洞挖掘与代码防护
-
什么叫漏洞
- 1 因代码没有完整的校验,造成了内存结构的破坏
-
如何发现漏洞
2.1 确定危险函数,
-
如何利用漏洞
-
如何防止漏洞
4.1 NX :栈不可执行(dep )–rop
4.2 aslr:指令地址随机化 ----->offset是固定的
4.3 canary -fstack-protector-all"A -fno-stack-protectorZ
4.4 RELRO
一、NX(Windows中的DEP)
NX:No-eXecute、DEP:Data Execute Prevention
也就是数据不可执行,防止因为程序运行出现溢出而使得攻击者的shellcode可能会在数据区尝试执行的情况。
gcc默认开启,选项有:
gcc -o test test.c // 默认情况下,开启NX保护
gcc -z execstack -o test test.c // 禁用NX保护
gcc -z noexecstack -o test test.c // 开启NX保护
二、PIE(ASLR)
PIE:Position-Independent Excutable、ASLR:Address Space Layout Randomization
-
fpie/fPIE:需要和选项-pie一起使用开启pie选项编译可执行文件使得elf拥有共享库属性,可以在内存任何地方加载运行。与之相似的还有fpic/fPIC,关于其说明于https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html
-
区别在于fpic/fPIC用于共享库的编译,fpie/fPIE则是pie文件编译的选项。文档中说 pic(位置无关代码)生成的共享库只能链接于可执行文件,之后根据自己编译简单C程序,pie正常运行,即如网上许多文章说的 pie
选项生成的位置无关代码可假定于本程序,但是我也没看出fpie/fPIE有啥区别,只是宏定义只为1和2的区别,貌似…编译命令(默认不开启PIE):
gcc -fpie -pie -o test test.c // 开启PIE
gcc -fPIE -pie -o test test.c // 开启PIE
gcc -fpic -o test test.c // 开启PIC
gcc -fPIC -o test test.c // 开启PIC
gcc -no-pie -o test test.c // 关闭PIE
- 而ASLR(地址空间随机化),当初设计时只负责栈、库、堆等段的地址随机化。ASLR的值存于/proc/sys/kernel/randomize_va_space中,如下:
0 - 表示关闭进程地址空间随机化。
1 - 表示将mmap的基址,stack和vdso页面随机化。
2 - 表示在1的基础上增加栈(heap)的随机化。(默认)
更改其值方式:echo 0 > /proc/sys/kernel/randomize_va_space
vDSO:virtual dynamic shared object;
mmap:即内存的映射。
PIE 则是负责可执行程序的基址随机。
PIE为ASLR的一部分,ASLR为系统功能,PIE则为编译选项。
注: 在heap分配时,有mmap()和brk()两种方式,由malloc()分配内存时调用,分配较小时brk,否则mmap,128k区别。
三、Canary(栈保护)
Canary对于栈的保护,在函数每一次执行时,在栈上随机产生一个Canary值。之后当函数执行结束返回时检测Canary值,若不一致系统则报出异常。
Canary值(cookies)置于缓冲区和控制数据之间,当缓冲区溢出,该值被覆写,从而可以检测以判断是否运行出错或是受到攻击。缓解缓冲区溢出攻击。
- 讲一下绕过手法
1). 泄露栈中的canary
canary设计是以“x00”结尾,本意就是为了保证canary可以截断字符串。泄露栈中canary的思路是覆盖canary的低字节,来打印出剩余的canary部分。
泄露条件:
- 存在栈溢出漏洞 可以将存在于
- 栈上的可控变量进行输出
- .逐位爆破canary
在某些pwn题中存在fork函数,且程序开启了canary保护,当程序进入到子进程的时候,其canary的值和父进程中canary的值一样,在一定的条件下我们可以将canary爆破出来;需要必备的条件就是程序中存在栈溢出的漏洞,并且可以覆盖到canary的位置,那么我们就可以把canary一位一位的爆破出来
四、RELRO(RELocation Read Only)
在Linux中有两种RELRO模式:”Partial RELRO“ 和 ”Full RELRO“。Linux中Partical RELRO默认开启。
Partial RELRO:
编译命令:
gcc -o test test.c // 默认部分开启
gcc -Wl,-z,relro -o test test.c // 开启部分RELRO
gcc -z lazy -o test test.c // 部分开启
该ELF文件的各个部分被重新排序。内数据段(internal data sections)(如.got,.dtors等)置于程序数据段(program's data sections)(如.data和.bss)之前;
无 plt 指向的GOT是只读的;
GOT表可写(应该是与上面有所区别的)。