缓冲区溢出攻击

概念:

缓冲区——程序用来保存用户输入数据、程序临时数据的内存空间,本质为数组。
缓冲区溢出攻击——攻击者利用程序漏洞,将自己的攻击代码植入有缓冲区溢出漏洞的程序执行体中,改变该程序的执行过程,来获取目标系统的控制权。如果用户输入的数据长度超出了程序为其分配的内存空间,这些溢出的数据就会覆盖程序为其他数据分配的内存空间,形成缓冲区溢出。通过缓冲区溢出攻击,一个用户可在匿名或拥有一般权限用户的情况下获取系统最高控制权。随意的往缓冲区内填充数据使其溢出只会产生段错误,而无法达到攻击的目的。常见的通过缓冲区溢出攻击来获取系统最高控制权的方式例如通过制造缓冲区溢出,使程序运行一个用户shell,再通过shell执行其他命令。如果该程序属于root且拥有suid权限,攻击者就获得了一个有root权限的用户shell,可以对系统进行任意操作了。
段错误——访问的内存超出了系统给这个程序分配的内存空间。
shell——命令语言,通常指命令行式shell,是操作系统最外面的一层。管理用户与操作系统的交互,等待用户输入,向操作系统解释用户的输入,并且处理各种各样的操作系统的输出结果。基本上是一个命令解释器,接受用户命令,然后调用相应的应用程序。其中又分为交互式与非交互式shell。
shellcode——是用来发送到服务器利用特定漏洞的代码,一般可以获取权限。通常作为数据发送给受攻击服务器,是溢出程序和蠕虫病毒的核心。
suid权限——一种特殊权限,当文件属主的x权限被s代替,表示被设置了suid,若属主位没有x权限会显示为大写S,表示有故障(权限无效)。被设置了suid的文件启动为进程后,其进程的属主为原文件的属主,suid只能作用在二进制程序上,不能作用在脚本,且设置在目录无意义。执行suid权限的程序时,此用户将继承此程序的所有者权限。
因为被攻击程序拥有suid权限,所以该程序在运行时,攻击者通过程序运行的用户shell,继承了root权限,可以对系统做任意操作。

原理:

一:向有漏洞程序的缓冲区中注入攻击字符串
二:利用漏洞改写内存的特定数据,如返回地址,使程序执行流程跳转到预先植入的shellcode
三:执行该shellcode使攻击者取得被攻击主机的控制权
这会导致系统受到三方面的攻击:
一:导致数据被修改,是针对完整性的攻击
二:导致数据不可获取的拒绝服务攻击,是针对可得性的攻击
三:导致敏感信息被获取,是针对机密性的攻击
攻击方式:
缓冲区溢出攻击技术繁多。以攻击原理分类可分为堆溢出、栈溢出、单字节溢出和格式化字符串溢出等;以攻击方式分类,可分为本地溢出和远程溢出。

在堆栈中以空操作指令NOP以及shellcode填充变量的内存空间,使内存溢出后将shellcode的地址覆盖到调用函数的返回地址,使程序在调用函数返回地址使执行shellcode语句,攻击者便获得了主机的控制权,如果该程序以root运行那么攻击者就获得了root权限,完全控制了被攻击的主机。

堆溢出攻击技术:

堆(HEAP)是应用程序动态分配的一块内存区,在操作系统中,大部分内存区由内核级动态分配,但HEAP段由应用程序分配,编译时被初始化。非初始化的数据段(BSS)存放静态变量,被初始化为零。
大部分操作系统中,HEAP段向上增长(即向高地址方向增长),那么在一段程序中声明两个静态变量,先声明的变量地址小于后声明的变量地址。
例如下面的一段漏洞程序:

Static char buffer[50];
Static int (* funcptr)();
while(* str){
*buffer++ = *str;//字符串复制
*str++;}
*funcptr();

低地址 高地址

…… —— buffer[50] —— funcptr —— …… <-堆中的变量存储

funcptr是函数指针,实质上是函数入口地址。由于该段程序在做字符串复制时未做边界检查,所以攻击者能够覆盖funcptr函数指针的值。那么程序执行funcptr函数时,会跳转至被覆盖的地址的地方继续执行。若攻击者在缓冲区植入shellcode,使用shellcode的内存地址覆盖funcptr,这时调用funcptr时就会转为执行shellcode。

整型溢出攻击技术:

以造成溢出原因来分又能分为宽度溢出、运算溢出和符号溢出。
一、宽度溢出
使用了不用的数据类型存储整形数,尝试存储一个超过变量表示范围的大数到变量中,同样的将短类型变量赋值给长类型也可能存在问题。
二、运算溢出
在运算过程中造成的整型数溢出最常见,就是在对整型数变量运算时没有考虑边界范围,造成运算后数值超出它的内存,那么其后用这一运算结果运行的程序均运行错误。
三、符号溢出
一般长度变量都使用无符号整型数,如果忽略了符号,进行安全检查时就可能出现问题。
典型例子:
Apache HTTP Server分块编码漏洞
分块编码方法时一种Web用户向服务器提交数据的传输方式,在HTTP1.1协议中定义。当服务器收到分块编码数据时,会分配一个缓冲区用来存放,如果数据大小不确定,那么客户端会用一个提前分配好的分块大小向服务器端提交数据。
Apache服务器默认提供对分块编码支持。Apache使用一个有符号变量存储分块长度,另外分配一个固定大小的堆栈缓冲区来存储分块数据。出于安全考虑,将分块数据复制到缓冲区之前,会检查分块长度,若分块长度大于缓冲期长度,就至多复制缓冲区长度的数据。但在检查前,没有将分块长度转换为无符号数进行比较。若攻击者将分块长度设置为负值,就能绕过以上安全检查,而Apache就会将一个超长(至少大于0x80000000字节)的分块复制到缓冲区,造成缓冲区溢出。具体引发漏洞的代码如下:

API_EXPORT(long) ap_get_client_block(request_rec *r, char *buffer, int bufsiz)
//漏洞发生在这个函数中,bufsiz是用户提交的buffer长度,是一个有符号的整型变量
{
…
len_to_read = (r->remaining > bufsiz) ? bufsiz : r->remaining;
//这里判断bufsiz和r->remaining哪个小,就用哪个作为复制字符串的长度,如果用户提交的buffer长度即bufsiz超过0x80000000时,由于bufsiz是有符号的整型数,因此它一定是一个负数,就肯定小于r->remaining,就绕过了安全检查

len_read = ap_bread(r->remaining->client , buffer , len_to_read);
if(len_read <= 0){
r->remaining->keepalive = -1
return -1;
}
ap_bread()函数的处理如下:
API_EXPORT(int) ap_bread(BUFF *fb , void *buf , int nbyte)
{memcpy(buf , fb->inptr , nbyte);}//这里采用memcpy复制缓冲区,复制长度是用户提交的buffer大小,由于之前绕过了长度安全检查,会发生缓冲区溢出

在Windows下利用此漏洞可以跳转到异常的内存地址,在ap_read()函数中,攻击者可通过构造len_to_read长度,利用memcpy的反向复制机制,实施攻击行为。

格式化字符串溢出攻击技术:

printf是c语言中少有的支持可变参数的库函数。printf系列函数被调用时,从格式字符串中依次读取字符,遇到格式化字符时,就按其从输出表项对应的变量中读取数据,再按照控制字符所规定的格式输出。
格式化字符串漏洞的产生根源主要源于对用户输入未进行过滤,这些输入数据都作为数据传递给某些执行格式化操作的函数,如printf,sprintf,vprintf,vprintf。恶意用户可以使用“%s”,”%x"来得到堆栈的数据,甚至可以通过"%n"来对任意地址进行读写,导致任意代码读写。
当printf在输出格式化字符串的时候,会维护一个内部指针,当printf逐步将格式化字符串的字符打印到屏幕,当遇到%的时候,printf会期望它后面跟着一个格式字符串,因此会递增内部字符串以抓取格式控制符的输入值。这就是问题所在,printf无法知道栈上是否放置了正确数量的变量供它操作,如果没有足够的变量可供操作,而指针按正常情况下递增,就会产生越界访问。甚至由于%n的问题,可导致任意地址读写。
攻击者可利用形似“%nu”(其中n为任意整数值)的格式控制符得到任意大小的输出字符个数,再利用%n将其个数压入栈中。
例如snprintf中

char str[80];
snprintf(str , 80 , format);//format为外部输入字符串,省略输出表项

在format的开始放入要改写的内存地址再用5个%x跳过20字节无关数据。当snprintf处理format字符串时,先将format中放入的内存地址复制到str数组,然后根据格式化控制符从堆栈中读取数据。如果在format中加入%n那么当前输出的字符个数会被写入在format预设地址中。
因此要利用此漏洞,可先在程序中植入shellcode,再利用格式化字符串的漏洞修改函数返回地址为shellcode的地址,那么当程序返回时,就会执行shellcode。

单字节溢出攻击技术:

eip:寄存器存放下一个CPU指令存放的内存地址,当CPU执行完当前的指令后,从EIP寄存器中读取下一条指令的内存地址,然后继续执行。
ebp:寄存器存放当前线程的栈底指针。
esp:寄存器存放当前线程的栈顶指针。
在AT&T的汇编语法中寄存器前要加%。

单字节溢出攻击往往发生于程序漏洞只允许输入多于缓冲区一个字节的数据时。
例如:

int i 
char  buf[256];
for(i = 0; i <= 256 ; i++)
	buff[i] = sm[i];

如上,最多只能多覆盖堆栈中的一个字节,不过在一定条件下仅利用这一个字节就可以达到攻击的目的。
当执行call指令时,进程首先将%eip和%ebp压入堆栈;然后将当前堆栈地址复制到%ebp中,再为局部变量分配空间;整型变量i占4个字节,buf[]占256个字节(0x100),因而%esp减少0x104,可见多出的一个字节应该覆盖到压入堆栈的%ebp的值的低字节。
调用结束时,%ebp的值会被复制到%esp中;然后%ebp再从堆栈中恢复,因此,可以改变%ebp的值,但只能修改%ebp的最后一个字节。
当进程从一个函数返回时,%ebp(已改变)中的值复制到%esp中作为新的堆栈指针,进程从堆栈中弹出保存的ebp到%ebp中(%ebp恢复正常),然后继续弹出保存的eip到%eip中继续执行。
而当程序返回到上一层调用时,%ebp中改变的值已被复制到%esp中作为新的堆栈指针,这时堆栈指针的值已被改变异常。然后,程序按照被改变的%esp弹出%ebp和%eip再从%eip处继续执行。
那么在缓冲区存放shellcode及伪造的上层函数返回地址,此地址指向shellcode,然后用一个字节覆盖已保存的ebp低字节,这个字节一定要小于它原来的值,这样修改的值就有可能指向缓冲区内放置的伪造的返回地址前四个字节的位置,那么当上层函数返回时,进程就会跳转至shellcode处继续执行。

溢出保护技术:

一:要求程序设计者编写正确的代码。通过学习安全编程、进行软件质量控制、使用源码级纠错工具达到目标。
二:选择合适的编译器。进行数组边界检查。编译时加入条件,如canary保护、StackGuard思想、Stack Cookie等。、Canary保护机制:在一个函数入口处从内存的某一个地方获取一个值,可以想象成是Cookie,存到栈中,在程序要返回时,判断栈中的这个cookie是否正确,如果不正确则判断为栈溢出。因为cookie是从内存一个位置的地方获取的,值同样未知,当我们进行栈溢出攻击时,控制ret跳转的值,肯定会把cookie覆盖掉,导致程序判断为栈溢出,程序退出攻击失败。
StackGuard:StackGuard是GCC编译器的补丁,它在返回地址后面加上额外的字节,通过检查该字节的完整性来确定是否发生溢出。
Cookie保护机制:Windows操作系统为保护函数返回地址被恶意修改,在栈中函数返回地址前增加了一个随机数,也成Cookie值。对于储存在临时缓冲区的函数,在执行操作前,将程序中一个全局的cookie值保存到函数返回地址前,并在函数返回前判断该cookie值是否与全局cookie相同,如果不同则触发异常。
三:选择合适的编程语言。c/c++出于效率的考虑,不检查数组的边界,这是语言的固有缺陷。
四:RunTime保护。可以进行二进制地址重写,Hook危险函数等技术。
五:操作系统层面。可以采用非执行缓冲区技术。缓冲区是存放数据的地方,可以在硬件或操作系统层次上强制缓冲区的内容不可执行。许多内核补丁都可以用来阻止缓冲区执行。
六:硬件:X86CPU上采用4GB平坦模式,数据段和代码段的线性地址是重叠的,页面只要可读就可以执行,诸多内核补丁才会费尽心机设计了各种方法来使数据段不可执行。Alpha、PPC、PA-RISC、SPARC、SPARC64、AMD64、IA64都提供了页执行bit位。Intel及AMD新增加的页执行bit位称为NX安全技术。Windows XP SP2及Linux Kernel 2.6都支持NX。
NX:全名为No eXecute即“禁止执行”,把记忆体区域分隔为只供储存处理器指令集,或只供数据使用。使用NX的记忆体代表仅供数据使用,处理器的指令集并不在这些区域存储。防止了多数缓冲区溢出攻击将恶意指令集放置在其他程序的数据储存区并执行。

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值