一种缓冲区溢出漏洞的定位方法与装置与流程

文档序号:13760712阅读:366来源:国知局
一种缓冲区溢出漏洞的定位方法与装置与流程

本发明涉及一种缓冲区溢出漏洞的定位方法与装置,属于信息安全技术领域。



背景技术:

在信息安全领域,软件漏洞分析是非常重要的一环,在众多的漏洞类型中,缓冲区溢出漏洞是最常见的一种漏洞类型。缓冲区溢出,根据缓冲区的位置不同,又分为栈的溢出,和堆的溢出。栈缓冲区溢出,是指通过向程序的缓冲区写超出其长度的内容,造成缓冲区的溢出,从而破坏程序的堆栈,使程序转而执行攻击者构造的数据,以达到执行恶意代码的目的。

在分析漏洞产生的原因时,迅速地定位到漏洞发生点是非常必要的。如果把引发缓冲区溢出的函数调用称为溢出函数,那么溢出函数的定位就有着至关重要的作用。

目前业界对于如何定位溢出函数,基本的思路是栈回溯,即通过查看堆栈上的函数调用顺序来回溯定位溢出函数。函数调用会保存栈帧指针和返回地址,并由这些保存的栈帧指针在堆栈中构成一个称为调用栈的函数调用关系链。由于缓冲区溢出通常会破坏栈中的返回地址以及栈帧指针指向的内容,因此,通常溢出函数返回时,程序的执行流程会转向不可预料的地址,通常是恶意的shellcode代码。通过调试器定位到异常发生位置是比较容易的,但是获取原来的调用信息却是比较困难,原因在于缓冲区溢出覆盖了返回地址和栈帧指针,导致栈上的函数调用关系链被破坏,一旦这个链条被破坏,调试器会丢失掉这个调用关系。业界通常使用的栈回溯技术依赖于调用栈,在这种情况下并无法回溯到原来的调用者代码区,从而使得栈回溯失效。

业界有些研究人员提出了先通过静态反编译,记录下函数调用关系图,然后在结合动态执行漏洞样本,来定位溢出函数的方法。这种方法可以克服上述提到的由缓冲区溢出覆盖栈帧导致的函数调用关系丢失的问题,但是这种方法有两方面的不足,一是依赖于反编译工具的能力,二是当程序的执行路径不同时,会引起误报。

申请号200810089912.5的专利公开了一种故障定位的方法和装置。该方法包括:在由于函数调用异常导致进程出现异常的情况下,在程序空间中获取异常进程的程序指针的值和堆栈指针的值;根据获取的程序指针的值和堆栈指针的值获取堆栈指针指向的当前函数堆栈的大小以及当前函数堆栈的栈帧中所存储的返回指令;根据当前函数堆栈的大小和堆栈指针的值获取当前函数堆栈之后的函数堆栈的栈帧中存储的函数的返回指令;查找异常进程的可执行文件,并根据查找的可执行文件查找异常进程的符号表,根据在当前栈帧和其它栈帧中获取的返回指令在符号表中查找相应的函数。该专利的核心是利用栈回溯方法来做代码异常的位置定位,此种栈回溯方法是利用的栈上的有效数据。

申请号201510170817.8的专利公开了一种基于函数调用的缓冲区溢出漏洞动态检测方法。该方法包括如下步骤:首先获取被测程序的函数调用指令地址和返回指令地址,构建输入参数、运行被测程序;当函数调用发生,获取基址寄存器中的值EBP_B;在函数调用结束时,获取基址寄存器中的值EBP_A;若EBP_B≠EBP_A,则记录漏洞并报警;若EBP_B=EBP_A,则判断无漏洞;重复上述过程直至被测程序运行结束,继续获取该次运行的函数调用信息,与软件异常行为模型进行匹配,若匹配,记录可能漏洞;若不匹配,则该次输入下程序的行为没有体现出缓冲区溢出漏洞的特征。构造大量输入重复检测。该方法能够进行动态检测,并提高检测效率。该专利是用来判断是否有缓冲区溢出漏洞的,也可以进一步定位溢出发生函数,它采取的方法是在函数调用之前记录当时的栈帧指针EBP,此时的EBP是调用者的栈帧指针,然后当函数调用结束后,再一次获取当时的栈帧指针EBP,然后通过比较两个EBP的值,判断是否此函数存在缓冲区溢出漏洞。这种方法的核心是要预先获取栈帧信息,通过比较预先获取的栈帧信息和实际得到的栈帧信息来判断是否溢出以及溢出位置。



技术实现要素:

本发明的目的是提供一种缓冲区溢出漏洞的定位方法与装置,尤其是用于缓冲区栈溢出漏洞的定位,该方法与装置可以在栈缓冲区溢出覆盖掉栈帧地址和函数返回地址的情况下,利用栈上的过时数据信息来重构函数调用关系链条,进一步通过重构的函数调用关系链条直接定位溢出函数。

为了达到上述目的,本发明的方法包括如下步骤:

步骤1:当缓冲区溢出发生后,使当前程序发生错误而中断执行,从而避免执行恶意代码;

步骤2:由当前ESP寄存器指向的地址作为起点,在栈上的过时数据中依次查找并确定过时栈帧指针和过时返回地址;

步骤3:所述过时返回地址的值即为溢出函数最后调用的子函数的返回地址,该返回地址对应的函数即为溢出函数。

其中,步骤1中使当前程序发生错误而中断执行的方法包括下列的一种或几种:开启操作系统的DEP功能,并且把漏洞程序使用DEP保护起来;更换操作系统的版本;更换操作系统的SP版本;更换操作系统的语言版本;更换漏洞程序的版本。

其中,步骤2中,对于栈由高地址向低地址增长的情况,栈上的过时数据对应的是地址小于当前ESP寄存器指向的地址的数据。

其中,在执行步骤2之前还包括判断当前函数的返回地址是否可以执行的判断步骤。

其中,对于当前函数的返回地址不可执行的情况,步骤2中查找并确定过时栈帧指针和过时返回地址的具体方法为:

(1)确定当前ESP寄存器指向的地址;

(2)从当前ESP寄存器指向的地址开始,沿着栈顶抬高的方向,在栈上的过时数据中查找满足下列条件1和2的第一个值,该值即为过时栈帧指针的值;

条件1:该值的大小属于栈的地址范围;

条件2:该值和当前ESP寄存器的值的差值很小,且所述差值为当前平台整型数长度的倍数;

(3)从所述过时栈帧指针的地址开始,在栈顶下降的方向找到与其相邻的值,该值即为过时返回地址。

其中,对于当前函数的返回地址可以执行的情况,步骤2中查找并确定过时栈帧指针和过时返回地址的具体方法为:

(1)确定当前ESP寄存器指向的地址;

(2)从当前ESP寄存器指向的地址开始,沿着栈顶抬高的方向,在栈上的过时数据中查找一个值,该值的大小与当前EIP寄存器的值的差值很小,将查找到的满足所述条件的第一个值作为中间过时返回地址;

(3)从所述中间过时返回地址的地址开始,在栈顶抬高的方向找到与其相邻的值,该值即为中间过时栈帧指针;

(4)从所述中间过时栈帧指针的地址开始,沿着栈顶抬高的方向,在栈上的过时数据中查找一个值,该值等于所述中间过时栈帧指针的地址值,将查找到的满足所述条件的第一个值作为过时栈帧指针;

(5)从所述过时栈帧指针的地址开始,在栈顶下降的方向找到与其相邻的值,该值即为过时返回地址。

此外,为了达到上述目的,本发明的装置包括:

中断保护模块,用于当缓冲区溢出发生后,使当前程序发生错误而中断执行,从而避免执行恶意代码;

过时数据查找模块,用于由当前ESP寄存器指向的地址作为起点,在栈上的过时数据中依次查找并确定过时栈帧指针和过时返回地址;

溢出函数定位模块,用于将所述过时返回地址的值作为溢出函数最后调用的子函数的返回地址,该返回地址对应的函数即为溢出函数。

其中,所述中断保护模块中使当前程序发生错误而中断执行的具体处理包括下列的一种或几种:开启操作系统的DEP功能,并且把漏洞程序使用DEP保护起来;更换操作系统的版本;更换操作系统的SP版本;更换操作系统的语言版本;更换漏洞程序的版本。

其中,过时数据查找模块中对于栈由高地址向低地址增长的情况,栈上的过时数据对应的是地址小于当前ESP寄存器指向的地址的数据。

其中,还包括返回地址判断模块,用于判断当前函数的返回地址是否可以执行。

其中,对于当前函数的返回地址不可执行的情况,过时数据查找模块中查找并确定过时栈帧指针和过时返回地址的具体处理为:

(1)确定当前ESP寄存器指向的地址;

(2)从当前ESP寄存器指向的地址开始,沿着栈顶抬高的方向,在栈上的过时数据中查找满足下列条件1和2的第一个值,该值即为过时栈帧指针的值;

条件1:该值的大小属于栈的地址范围;

条件2:该值和当前ESP寄存器的值的差值很小,且所述差值为当前平台整型数长度的倍数;

(3)从所述过时栈帧指针的地址开始,在栈顶下降的方向找到与其相邻的值,该值即为过时返回地址。

其中,对于当前函数的返回地址可以执行的情况,过时数据查找模块中查找并确定过时栈帧指针和过时返回地址的具体处理为:

(1)确定当前ESP寄存器指向的地址;

(2)从当前ESP寄存器指向的地址开始,沿着栈顶抬高的方向,在栈上的过时数据中查找一个值,该值的大小与当前EIP寄存器的值的差值很小,将查找到的满足所述条件的第一个值作为中间过时返回地址;

(3)从所述中间过时返回地址的地址开始,在栈顶抬高的方向找到与其相邻的值,该值即为中间过时栈帧指针;

(4)从所述中间过时栈帧指针的地址开始,沿着栈顶抬高的方向,在栈上的过时数据中查找一个值,该值等于所述中间过时栈帧指针的地址值,将查找到的满足所述条件的第一个值作为过时栈帧指针;

(5)从所述过时栈帧指针的地址开始,在栈顶下降的方向找到与其相邻的值,该值即为过时返回地址。

本发明可以在栈缓冲区溢出覆盖掉栈帧地址和函数返回地址的情况下,利用栈上的过时数据信息来重构函数调用关系链条,进一步通过重构的函数调用关系链条直接定位溢出函数。通过以上方法,解决了由于栈缓冲区溢出覆盖返回地址和栈帧地址导致的函数调用关系破坏的问题,另外从思路上不再采用栈调用函数依次回溯的方式,而是采用直接定位溢出函数的新方法,利用栈上的过时数据来定位漏洞函数,通过对不同情形做细分处理,使得过时数据从不可用变得可用,可以快速定位溢出函数和溢出地址。

本发明不仅可以应用在漏洞定位领域,同样可以应用在定位程序异常点,快速定位出错地址上,比如各种硬件平台上的代码排错,各种中间层虚拟机字节码的排错等,都可以使用本发明的思路。

附图说明

图1为栈结构和操作示意图;

图2为本发明当程序栈缓冲区溢出发生时,从当时的状态来定位漏洞溢出函数的步骤流程图。

图3为本发明装置的组成示意图。

具体实施方式

下面结合附图和实施例,对本发明进行详细描述。

本发明的思路是利用栈上的过时数据重构函数调用关系来定位到溢出函数,和常规的栈回溯方式以及函数调用流程图事先测绘方式有着本质的区别。由于栈上的过时数据的变化本身是杂乱无章的,所以常规的一些方法都没有意识到栈上面的过时数据的作用,本发明是根据栈上过时数据和函数调用子函数的关系,提出的一种快速定位溢出函数的新方式。

本发明中,把引发缓冲区溢出的函数调用称为“溢出函数”。

本发明中,对于在内存中栈由高地址向低地址增长的情况,“过时数据”是指地址小于ESP寄存器指向的地址的那些内存单元中存储的数据。

本发明实施例中的一种栈结构如附图1所示。从栈底到栈顶的方向,依次存储有函数调用的参数、返回地址Ret、EBP寄存器的值和函数的局部变量(即缓冲区)。

方法步骤1的实施例:

在溢出发生后,代码执行到返回地址时,有几种情况,一是返回地址是漏洞利用者精心构造的地址,那么攻击者就控制了代码执行流程,转而去执行shellcode恶意代码;二是此地址不可执行,那么调试器就会中断在此地址,由于函数在返回时有可能做堆栈平衡,所以最终的ESP指向的位置会在函数的返回地址偏移一些字节;三是返回地址是可以执行的,但是不是漏洞利用者设想的代码,如JMP ESP之类的跳转指令,此时代码执行流程会沿着跳转到的地址继续向下执行,但是由于上下文环境不正确,在执行几条指令后会由于异常而停止,调试器就会中断在此时。这种情况下,执行的代码对栈有操作的话,就会影响栈的布局,使得ESP指针在栈上上下浮动。

对于第一种情况,如果shellcode恶意代码得到了执行,说明漏洞成功触发,并且成功利用,这显然是不希望发生的情况。本发明中,为了避免在发生缓冲区溢出时程序转去执行恶意代码以及实现缓冲区溢出漏洞的定位,在出现缓冲区溢出情况时,首先需要的是采取措施使得程序因缓冲区溢出而发生错误中断执行。这时可以人为设置环境使漏洞利用失败,具体可以采取的措施包括但是不限于以下措施:

(1)开启操作系统的DEP功能,并且把漏洞程序使用DEP保护起来,这样一来栈上的数据就不能得到执行,漏洞利用就会失败;

(2)更换操作系统的版本,如把windows 7改成windows 8;

(3)更换操作系统的SP版本,如把SP1改成SP2;

(4)更换操作系统的语言版本,如中文版改成英文版、繁体版等;

(5)更换漏洞程序的版本,如把存在漏洞的版本更换为打上补丁的版本。

当如上所述采取措施使得漏洞利用失败,此时第一种情况就转化成第二种情况或者第三者情况。

方法步骤2的实施例:

对于步骤2,参见附图2,首先需要判断返回地址是否可以执行,然后分为两种情况分别处理。

在返回地址不可执行的情况下,参见附图2,处理方式如下:

步骤S101:找到ESP寄存器的当前值,其指向内存当中的某个地址。例如,当前ESP寄存器的值为0x10101010,其指向的内存地址即为0x10101010。

步骤S102:从ESP寄存器的当前值指向的内存地址开始,即从地址0x10101010开始,沿着栈顶抬高的方向,即内存地址减小的方向,在栈上的过时数据中查找这样的一个值。这个值满足如下两个条件:

条件1:该值的大小属于栈的地址范围;

条件2:该值的大小与当前ESP寄存器的值(即0x10101010)的差值很小,例如小于64字节,而且为此平台整型数长度的倍数,以32位平台为例,则为4的倍数,一般取值多在4,8,12,16,20等。

查找到的同时满足上述两个条件的第一个值即为过时栈帧指针OLD_EBP的值。在此实施例中,假设从地址0x10101010开始,查找到的第一个满足上述条件的值为0x10101004,即(0x10101010-12),该值所在的内存地址假设为0x10101000。那么,此时过时栈帧指针OLD_EBP的值即为0x10101004。

步骤S103:如果按照步骤S102的方法不能找到过时栈帧指针OLD_EBP,则定位失败,此方法失效。

步骤S104:以查找到的过时栈帧指针OLD_EBP的地址为起点,即地址0x10101000为起点,在栈顶下降的方向,即内存地址增加的方向,找到与其相邻的值,在32位平台上,该值的长度为4字节。查找到的值即为过时返回地址OLD_RET。

如果返回地址可以执行,但是不是漏洞利用者设想的代码,如JMP ESP之类的跳转指令,此时代码执行流程从返回地址继续向下执行,由于上下文环境不正确,在执行几条指令后会由于异常而停止,调试器就会中断在此处。

在返回地址可以执行的情况下,参见附图2,处理方式如下:

步骤S201:找到ESP寄存器和EIP寄存器的当前值,EIP表示此时异常的执行地址,ESP表示此时的栈顶指针。例如,当前ESP寄存器的值为0x10101010,其指向的内存地址即为0x10101010。

步骤S202:从ESP寄存器的当前值指向的内存地址开始,即从地址0x10101010开始,沿着栈顶抬高的方向,即内存地址减小的方向,在栈上的过时数据中查找这样的一个值。这个值的大小和当前EIP寄存器值的差值很小,一般不会超过256字节,查找到的第一个值即为中间过时返回地址OLD_RET1。例如,从地址0x10101010开始,查找到的第一个满足上述条件的值为(EIP-4),而该值所在的内存地址假设为0x10101000,则此时中间过时返回地址OLD_RET1为(EIP-4)。

步骤S203:判断是否可以找到上述中间过时返回地址OLD_RET1,如果不能找到,则此方法失效。

步骤S204:从所述中间过时返回地址OLD_RET1的地址开始,在栈顶抬高的方向找到与其相邻的值,在32位平台上,长度为4字节,该值即为中间过时栈帧指针OLD_EBP1,记录下该中间过时栈帧指针OLD_EBP1所在的内存地址。即从地址0x10101000开始,再减去4字节,为0x10100FFC。

步骤S205:从所述中间过时栈帧指针OLD_EBP1的地址开始,即从地址0x10100FFC开始,沿着栈顶抬高的方向,在栈上的过时数据中查找值等于0x10100FFC的内存单元,将查找到的满足所述条件的第一个值作为过时栈帧指针OLD_EBP2。例如,查找到的值等于0x10100FFC的第一个内存单元的地址为0x10100FF0。

步骤S206:判断是否可以找到过时栈帧指针OLD_EBP2,如果不能找到,则此方法失效。

步骤S207:从所述过时栈帧指针OLD_EBP2的地址开始,即从地址0x10100FF0开始,在栈顶下降的方向,即内存地址增加的方向,找到与其相邻的值,在32位平台上,该值的长度为4字节。查找到的值即为过时返回地址OLD_RET2。

方法步骤3的实施例:

在步骤2中查找到的过时返回地址OLD_RET、OLD_RET2的值是溢出函数最后调用的子函数的返回地址,这个地址属于哪个函数,哪个函数就是溢出函数。所述过时返回地址OLD_RET、OLD_RET2的值即为溢出函数最后调用的子函数的返回地址,该返回地址对应的函数即为溢出函数。

装置的实施例:

在本实施例中,提供了一种缓冲区溢出漏洞的定位装置,尤其是用于缓冲区栈溢出漏洞的定位。如附图3所示,该装置包括:

中断保护模块301,用于当缓冲区溢出发生后,使当前程序发生错误而中断执行,从而避免执行恶意代码;

过时数据查找模块302,用于由当前ESP寄存器指向的地址作为起点,在栈上的过时数据中依次查找并确定过时栈帧指针OLD_EBP和过时返回地址OLD_RET;

溢出函数定位模块303,用于将所述过时返回地址OLD_RET的值作为溢出函数最后调用的子函数的返回地址,该返回地址对应的函数即为溢出函数。

上述各个模块的具体组成和工作方式与前述的方法实施例相对应。

综上所述,之前的方法一直是着眼于栈上的非过时数据,即通过栈数据回溯的方法来定位漏洞函数和漏洞地址,本发明是利用栈上的过时数据来定位漏洞函数,通过对不同情形做细分处理,使得过时数据从不可用变得可用,可以快速定位溢出函数和溢出地址。

以上所述仅为本发明的优选实施例而已,并不用于限制本发明,对于本领域的技术人员来说,本发明可以有各种更改和变化。凡在本发明的精神和原则之内,所作的任何修改、等同替换、改进等,均应包含在本发明的保护范围之内。

当前第1页1 2 3 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1