EagleBear2002 的博客

这里必须根绝一切犹豫,这里任何怯懦都无济于事

软件安全-03-典型软件漏洞分析

摘要

  1. 什么是缓冲区溢出漏洞?
  2. 什么是栈溢出?栈溢出漏洞如何利用?
  3. 什么是堆溢出?堆溢出漏洞如何利用?
  4. 什么是格式化字符串漏洞?该漏洞如何利用?
  5. 针对缓冲区溢出漏洞,Windows 平台设置了哪些保护机制?

什么是缓冲区溢出漏洞?

内存结构

Win32 系统中,进程使用的内存按功能可以分 4 个区域

缓冲区

程序中所使用的缓冲区可以是堆区和栈区,也可以是存放静态变量的数据区。

由于进程中各个区域都有自己的用途,根据缓冲区利用的方法和缓冲区在内存中所属区域,其可分为栈溢出和堆溢出。

缓冲区溢出漏洞

缓冲区溢出漏洞就是在向缓冲区写入数据时,由于没有做边界检查,导致写入缓冲区的数据超过预先分配的边界,从而使溢出数据覆盖在合法数据上而引起系统异常的一种现象。

目前,缓冲区溢出漏洞普遍存在于各种操作系统(Windows、Linux、Solaris、Free BSD、HP-UX 以及 IBM AIX),以及运行在操作系统上的各类应用程序中。

什么是栈溢出?栈溢出漏洞如何利用?

函数的栈帧

在程序设计中,栈通常指的是一种后进先出的数据结构。

相对于广义的栈而言,栈帧是操作系统为进程中的每个函数调用划分的一个空间,每个栈帧都是一个独立的栈结构,而系统栈则是这些函数调用栈帧的集合。

系统栈由系统自动维护,用于实现高级语言中函数的调用。

当函数被调用时,系统会为这个函数开辟一个新的栈帧,并把它压入栈区中,所以正在运行的函数总是在系统栈区的栈顶(本书称为:当前栈帧)。当函数返回时,系统会弹出该函数所对应的栈帧空间。

栈帧的生长方向是从高地址向低地址增长的。

  • ESP:扩展栈指针(Extended Stack Pointer)寄存器,其存放的指针指向当前栈帧的栈顶。
  • EBP:扩展基址指针(Extended Base Pointer)寄存器,其存放的指针指向当前栈帧的栈底。

显然,ESP 与 EBP 之间的空间即为当前栈帧空间。

一个函数栈帧中主要包含如下信息。

  1. 前一个栈帧的栈底位置,即前栈帧 EBP,用于在函数调用结束后恢复主调函数的栈帧(前栈帧的栈顶可计算得到)。
  2. 该函数的局部变量。
  3. 函数调用的参数。
  4. 函数的返回地址 RET,用于保存函数调用前指令的位置,以便函数返回时能恢复到调用前的代码区中继续执行指令。

函数调用的步骤

栈溢出漏洞基本原理

例 3-2 修改相邻变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void fun() {
char password[6] = "ABCDE";
char str[6];
gets(str);
str[5] = '\0';
if (strcmp(str, password) == 0)
printf("OK.\n");
else
printf("NO.\n");
}

int main() {
fun();
return 0;
}

栈溢出修改相邻变量

栈溢出后修改返回地址 RET

栈溢出后修改相邻变量这种漏洞利用对代码环境的要求比较苛刻。更常用的栈溢出修改的目标往往不是某个变量,而是栈帧中的 EBP 和函数返回地址 RET 等值。

接下来例 3-3 演示的是,将一个有效指令地址写入返回地址区域中,这样就可以让 CPU 跳转到我们希望执行的指令处,从而达到控制程序执行流程的目的。

栈溢出攻击

实际攻击中,攻击者通过缓冲区溢出改写的目标往往不是某一个变量,而是栈帧高地址的 EBP 和函数的返回地址等值。通过覆盖程序中的函数返回地址和函数指针等值,攻击者可以直接将程序跳转到其预先设定或已经注入到目标程序的代码上去执行。

栈溢出攻击是一种利用栈溢出漏洞所进行的攻击行动,目的在于扰乱具有某些特权运行的程序的功能,使得攻击者取得程序的控制权,如果该程序具有足够的权限,那么整个主机就被控制了。

1)JMP ESP 覆盖方法

在实际的漏洞利用中,由于动态链接库的装入和卸载等原因,Windows 进程的函数栈帧可能发生移位,即 Shellcode 在内存中的地址是动态变化的,所以上述采用直接赋地址值的简单方式在以后的运行过程中会出现跳转异常。

可以在覆盖返回地址的时候用系统动态链接库中某条处于高地址且位置固定的跳转指令所在的地址进行覆盖,然后再通过这条跳转指令指向动态变化的 Shellcode 地址。这样便能够确保程序执行流程在目标系统运行时可以被如期进行。

JMP ESP 覆盖方法是覆盖函数返回地址的一种攻击方式。考虑到函数返回时 ESP 总是指向函数返回后的下一条指令,根据这一特点,如果用指令 JMP ESP 的地址覆盖返回地址,则函数也可以跳转到函数返回后的下一条指令,而从函数返回后的下一条指令开始都已经被 Shellcode 所覆盖,那么程序就可以跳转到该 Shellcode 上并执行,从而实现了程序流程的控制。

SEH 覆盖方法

SEH 覆盖方法就是覆盖异常处理程序地址的一种攻击方式。由于 SEH 结构存放在栈中,因此攻击者可以利用栈溢出漏洞,设计特定的溢出数据,将 SEH 中异常函数的入口地址覆盖为 Shellcode 的起始地址或可以跳转到 Shellcode 的跳转指令地址,从而导致程序发生异常时,Windows 异常处理机制执行的不是预设的异常处理函数,而是 Shellcode。

什么是堆溢出?堆溢出漏洞如何利用?

堆的基本知识

堆与栈的区别

堆的结构

堆溢出漏洞及利用

如果能够修改链表节点的指针,在“卸下”和“链入”的过程中就有可能获得一次读写内存的机会。

DWORD Shoot

堆溢出利用的精髓就是用精心构造的数据去溢出覆盖下一个堆块的块首,使其改写块首中的前向指针(flink)和后向指针(blink),然后在分配、释放、合并等操作发生时伺机获得一次向内存任意地址写入任意数据的机会。

攻击者可以进而劫持进程,运行 shellcode。

Heap Spray

栈溢出和堆溢出相结合的一种技术。

首先将 shellcode 放置到堆中,然后在栈溢出时,控制函数执行流程,跳转到堆中执行 shellcode

TODO

什么是格式化字符串漏洞?该漏洞如何利用?

针对缓冲区溢出漏洞,Windows 平台设置了哪些保护机制?