缓存区溢出

2019-07-10  本文已影响0人  暑水

JVM:https://www.jianshu.com/p/a60d6ef0771b
顾名思义,缓冲区溢出的含义是为缓冲区提供了多于其存储容量的数据,就像往杯子里倒入了过量的水一样。通常情况下,缓冲区溢出的数据只会破坏程序数据,造成意外终止。但是如果有人精心构造溢出数据的内容,那么就有可能获得系统的控制权!

图1 进程地址空间分布

数据存放

图1是进程地址空间分布的简单表示。代码存储了用户程序的所有可执行代码,在程序正常执行的情况下:

函数栈

栈的主要功能是实现函数的调用。因此在介绍栈溢出原理之前,需要弄清函数调用时栈空间发生了怎样的变化。每次函数调用时,系统会把函数的返回地址(函数调用指令后紧跟指令的地址),一些关键的寄存器值保存在栈内,函数的实际参数和局部变量(包括数据、结构体、对象等)也会保存在栈内。这些数据统称为函数调用的栈帧,而且是每次函数调用都会有个独立的栈帧,这也为递归函数的实现提供了可能。

之所以会有缓冲区溢出的可能,主要是因为栈空间内保存了函数的返回地址。该地址保存了函数调用结束后后续执行的指令的位置,对于计算机安全来说,该信息是很敏感的。如果有人恶意修改了这个返回地址,并使该返回地址指向了一个新的代码位置,程序便能从其它位置继续执行。

栈溢出基本原理

上边给出的代码是无法进行溢出操作的,因为用户没有“插足”的机会。但是实际上很多程序都会接受用户的外界输入,尤其是当函数内的一个数组缓冲区接受用户输入的时候,一旦程序代码未对输入的长度进行合法性检查的话,缓冲区溢出便有可能触发!比如下边的一个简单的函数。

void fun(unsigned char *data)
{
    unsigned char buffer[BUF_LEN];
    strcpy((char*)buffer,(char*)data);//溢出点
}

这个函数没有做什么有“意义”的事情(这里主要是为了简化问题),但是它是一个典型的栈溢出代码。在使用不安全的strcpy库函数时,系统会盲目地将data的全部数据拷贝到buffer指向的内存区域。buffer的长度是有限的,一旦data的数据长度超过BUF_LEN,便会产生缓冲区溢出。

缓冲区溢出

由于栈是低地址方向增长的,因此局部数组buffer的指针在缓冲区的下方。当把data的数据拷贝到buffer内时,超过缓冲区区域的高地址部分数据会“淹没”原本的其他栈帧数据,根据淹没数据的内容不同,可能会有产生以下情况:

1、淹没了其他的局部变量。如果被淹没的局部变量是条件变量,那么可能会改变函数原本的执行流程。这种方式可以用于破解简单的软件验证。

2、淹没了ebp的值。修改了函数执行结束后要恢复的栈指针,将会导致栈帧失去平衡。

3、淹没了返回地址。这是栈溢出原理的核心所在,通过淹没的方式修改函数的返回地址,使程序代码执行“意外”的流程!

4、淹没参数变量。修改函数的参数变量也可能改变当前函数的执行结果和流程。

5、淹没上级函数的栈帧,情况与上述4点类似,只不过影响的是上级函数的执行。当然这里的前提是保证函数能正常返回,即函数地址不能被随意修改(这可能很麻烦!)。

如果在data本身的数据内就保存了一系列的指令的二进制代码,一旦栈溢出修改了函数的返回地址,并将该地址指向这段二进制代码的其实位置,那么就完成了基本的溢出攻击行为。

上一篇 下一篇

猜你喜欢

热点阅读