Linux栈溢出攻防原理

、前言

Linux下常用的拷贝函数(如strcpy、memcpy等)如果使用不规范,常常会导致栈溢出。也就是你的软件系统本身存在bug,这样就会成为别人攻击的目标。本文主要讲的是Linux系统如何给栈溢出增加防护网?攻击者又有什么手段绕过一层层防护网实现攻击?

 

2、栈溢出防御

2.1 地址随机化技术

Linux系统提供设置堆栈地址随机化技术,例如函数内部变量存在栈上,每次打印函数内部变量的地址,其值都是随机的。

 

用户可以通过读取或设置/proc/sys/kernel/randomize_va_space节点值对其属性进行修改。

 

其中0表示关闭地址随机化;2表示开启地址随机化。

 

Linux系统默认是开启了地址随机化技术的。

 

2.2 栈不可执行

当我们通过读取/proc/pid/maps会发现stack的权限是“rw-p”,这说明栈上的数据只有读写权限,没有执行权限。这样如果你把一段shellcode放到栈上,是无法执行的。

 

2.3 栈保护

在函数的入口和出口处加一段栈检测的汇编代码,用来检测rbp和返回地址是否被修改,这就是Linux的栈保护机制。

 

GCC编译的时候可以加-fstack-protector则开启栈保护机制,如果加上-fno-stack-protector则会取消栈保护机制。

 

可执行文件是否开启栈保护,可以objdump查看下汇编,如下是某函数的反汇编,可以确定该可执行文件开启了栈保护机制。

 

2.4 Intel X64改变函数参数存放方式

在Intel X86平台,函数的参数是压栈存放的,这样攻击者构造攻击函数的时候,攻击函数的参数直接放在栈上即可。但是在Intel X64平台上,函数的前6个参数是存在寄存器中的,这样提升了攻击者攻击的难度。

 

3、栈溢出攻击

3.1 Shellcode攻击

当程序执行call指令调用一个函数时,会把下一条指令的地址(返回地址)压栈,当这个函数执行完毕最终需要执行ret执行,该指令会从栈中取出返回地址给ip,程序继续执行。

 

所以针对栈溢出攻击,常规方法是修改栈中返回地址,使其指向一段shellcode。

 

如果这段shellcode存放在栈中,同时环境开启了栈不可执行话,这样的攻击就失效了,所以可以把shellcode存放在代码段中,就可以绕过栈不可执机制了。但是在代码段中新增代码涉及ELF文件的重新布局,这部分还是有一定难度的,后续细讲。

 

3.2 ReturnToLib技术

该技术是利用库函数代替shellcode实现攻击的一种方法。

 

具体讲,把攻击代码拆分,利用libc库函数,使得函数返回时,调用libc库函数来实现,这样就可以绕过栈不可执机制实现攻击。但是该技术存在一个问题,如果系统开启了地址随机化,libc的库函数每次运行的时候地址是随机的,这样攻击就失效了。

 

怎么解决地址随机化问题呢?需要寻找不变的量。ELF文件镜像本身是不变的,所以我们可以根据每个libc库函数的地址=libc基地址(变)+函数偏移(不变,readelf -s可查到)。

Eg. execve地址=运行中printf地址(变)-printf函数偏移(不变)+execve函数偏移(不变)

 

3.3 ReturnToProgramming

该技术是利用未随机化的模块内部的汇编代码,实现攻击的一种方法。

 

针对Intel X64平台,函数的前6个参数是存在寄存器中的,我们构造攻击的时候,需要寻找模块内部的汇编代码,实现控制流。

 

例如攻击代码需要执行setuid(0),假如模块内存存在”pop rdi ;ret”这样的汇编代码,则栈溢出时返回地址指向这样的汇编代码,同时往栈里一次压人参数0,setuid的函数地址。

 

4、后续

这里只是介绍了常见的栈溢出的攻防手段,后面会先针对Intel X64平台ROP攻击做深入分析。

 

欢迎扫码关注公众号“嵌入式Linux技术分享”,一起学习Linux吧

 

 

你可能感兴趣的:(Linux逆向)