缓冲区漏洞之内存溢出详解

          在所有漏洞中,缓冲区溢出漏洞可视为最简单、最常见的漏洞,缓冲区溢出漏洞的发现较早。缓冲区溢出漏洞的形成通常超过程序代码分配的缓冲区长度,导致相邻内存地址中的内容被覆盖,损坏内存中的堆栈或堆。将数据写入缓冲区时,通常称为shellcode。一般来说,程序代码的变量存储在内存堆栈上。因此,堆溢出和堆栈溢出成为缓冲区溢出的两个重要组成部分。一般情况下,堆栈溢出对应于以下危险函数(C/C++):gets()、strcat()、sprintf()、scanf()等。3.2.1栈缓冲区溢出原理栈溢出是指写入的数据超过栈允许的深度,从而在内存栈中写入shellcode,以覆盖函数的返回地址。函数在计算机中的返回地址保存在栈中。当栈溢出形成时,溢出的shellcode代码将覆盖栈中的返回地址,而不是攻击者指定的目的地地址。展示了栈溢出漏洞的形成过程。从原理图可以看出,当被调用的函数执行类似于strcpy()的操作时,设计好的shellcode将进入缓冲区。

如果shellcode片段大于开放式栈空间,且程序未检查栈溢出,则会发生栈溢出,并覆盖以下返回地址。当程序代码段执行到RET指令时,它会跳转到相应的内存地址,从而实现栈溢出的漏洞攻击。实现栈溢出漏洞的方法有两种,一种是通过指令jmpesp向后跳转实现溢出覆盖;另一种是通过覆盖返回地址实现向前跳转溢出覆盖。

堆也是一种基本的数据结构。与堆栈遵循的原则不同,其原理是先进先出。栈溢出和堆溢出发生时,其原理基本相同:由于缓冲区的容量不能满足存储的数据,导致溢出。然而,与栈稍有不同的是,堆通常由程序中的代码new()申请获取内存。因此,在使用溢出进行漏洞攻击时,需要使用GOT(全局环境)的虚拟函数表,并使用内存分配库的函数劫持程序流。与栈溢出原理相比,堆溢出原理更为复杂。一般有两种表现形式:内存信息泄露和控制流劫持。在程序代码中,堆通常通过程序new()方法完成;堆的释放还需要相应的函数:heapfree()、free()等。与栈溢出原理不同,堆缓冲区溢出是通过溢出数据覆盖相应的函数指针。

分享: