一、缓冲区基本概念
1.缓冲区:也称堆栈,是一种抽象的数据结构,物理上就是一段连续分配的内存空间。堆(heap)和栈(stack)是不同的两个概念,堆是由程序申请并释放的内存空间,而栈是由操作系统自动分配的内存空间。
堆和栈有两个特点:一是数据操作(进栈和出栈)遵循"后进先出"原则,就像往右底的竹筒里放乒乓球,最后放进去的必须是先取出来;二是堆栈的增长方向与内存地址增长方向相反,也就是堆栈是从内存的高地址向低地址增长的。
2. 指针:编程语言中的一个对象,是一个内存地址。
3. 寄存器:有限存储空间的高速存储部件,它们可用来暂存指令、数据和地址。以X86 32位CPU为例,其通常包含8个通用寄存器和1个指令指针寄存器。8个通用寄存器分别是EAX、EBX、ECX、EDX、ESI、EDI、ESP、EBP和指令指针寄存器EIP。其中ESP和EBP也被成为堆栈指针寄存器,在一个函数中,ESP和EBP共同决定了一个堆栈,其中ESP指向栈顶,EBP指向栈底。而指令指针寄存器(EIP)指向CPU要执行的下一条指令的地址(返回地址)。
二、缓冲区溢出攻击原理
缓冲区溢出是一种非常普遍也非常危险的漏洞,广泛存在于各种操作系统、应用软件中。漏洞的原因是由于程序员对数据没有进行严格的校验,攻击者可以通过向程序的缓冲区写入超过预定长度的数据,从而破坏程序的堆栈,导致程序执行流程的改变,使得攻击者可以操纵被攻击软件并执行攻击者设定的代码。
缓冲区溢出攻击分为栈溢出和堆溢出,下面用一个示例程序来说明缓冲区溢出(栈溢出)攻击
三、缓冲区溢出简单示例
程序作用:将用户输入的内容打印在屏幕上
Buffer.c
#include <stdio.h>
int main ( )
{
char name[8];
printf("Please input your name: ");
gets(name);
printf("you name is: %s!", name);
return 0;
}
这段程序的功能时显示输入的用户名称,在程序中,用于存放用户输入名称的变量name长度定义为8位,由于程序缺少必要的输入长度校验,当用户的输入值超过8位时,执行时会导致一个缓存溢出
例如用户输入用户名为"
shentongshentongshentongshen"时,由于输入值超过name定义的长度(程序申请缓冲区)。当程序将用户输入值保存到name的地址空间时,会继续向内存后续地址空间写入其余输入内容,进而覆盖了程序栈中存储的返回地址(即EIP)
这个EIP空间是返回地址,不能被“多出来的”字符填充
程序在需要调用并返回地址时,把EIP中存储的“aaaa”的ASCII码0x61616161作为下一条指令地址,CPU会试图执行0x61616161处的指令,而由于该内存并非运行程序所能访问,因此这个操作会被系统拒绝,因此产生错误
五、缓冲区溢出攻击过程
如果攻击者输入的内容是经过精确定义的,覆盖了EIP原有地址,使得程序跳转到攻击者覆盖进去的地址去执行下一条指令,而该地址处被攻击者预先放置了一段攻击代码,那么攻击者就可以执行这段攻击代码从而获得系统控制权或者执行其他攻击操作。
六、缓冲区溢出的防范措施
对用户而言,要防范缓冲区溢出攻击,需要及时安装安全补丁。即使是拥有最好的程序员,经过多年开发完善的软件,也很难彻底消除缓冲区溢出的问题。大量用户并非软件的开发者或专业的安全人员,不可能自己解决所有的安全问题,因此,安全补丁或更新程序时解决缓冲区溢出问题的有效办法。
而对于软件软件开发者来说,应对开发人员进行安全编码培训,了解缓冲区溢出攻击的概念及了解如何避免缓冲区溢出漏洞的产生。提高编写安全代码的能力是降低缓冲区溢出漏洞产生的有效办法
除此之外,现在操作系统中使用的虚拟技术对缓冲区溢出攻击有较好的保护作用。
还有哪些防范措施,欢迎大家评论区讨论,最后不要忘记点赞关注哈,谢谢