什么是缓冲区溢出?

当程序向缓冲区中写入数据的程序使该缓冲区的容量过载时,就会发生缓冲区溢出。这就像将 12 盎司的牛奶倒入 8 盎司的杯子中。

Share facebook icon linkedin icon twitter icon email icon

缓冲区溢出

学习目标

阅读本文后,您将能够:

  • 定义缓冲区
  • 解释缓冲区溢出及其如何被用于网络攻击
  • 了解谁最容易受到攻击以及如何防范缓冲区溢出攻击

什么是缓冲区溢出?

缓冲区溢出是一种异常现象,当软件向缓冲区中写入数据使缓冲区容量溢出时,会导致相邻存储器位置被覆盖。换句话说,过量的信息被传递到没有足够空间的容器中,而这些信息最终会替换相邻容器中的数据。

攻击者可以利用缓冲区溢出修改计算机的内存,以破坏或控制程序的执行。

Buffer Overflow

什么是缓冲区?

缓冲区或数据缓冲区是一个物理内存存储区,用于在将数据从一个位置移到另一位置时临时存储数据。这些缓冲区通常位于 RAM 内存中。计算机经常使用缓冲区来帮助提高性能。大多数现代硬盘驱动器都利用缓冲的优势来有效地访问数据,并且许多在线服务也使用缓冲区。例如,在线视频传送服务经常使用缓冲区以防止中断。流式传输视频时,视频播放器一次下载并存储 20% 的视频到缓冲区,然后从该缓冲区进行流式传输。这样,连接速度的小幅下降或快速的服务中断都不会影响视频流性能。

缓冲区旨在容纳特定数量的数据。除非利用缓冲区的程序具有内置指令以在将太多数据发送到缓冲区时丢弃数据,否则程序将覆盖缓冲区附近的内存中的数据。

攻击者可以利用缓冲区溢出来破坏软件。尽管这个隐患得到了很好的理解,但缓冲区溢出攻击仍然是困扰网络安全团队的主要安全问题。2014 年,由于 SSL 软件中的缓冲区溢出漏洞,一种被称为“心脏出血”的威胁使亿万用户受到攻击。

攻击者如何利用缓冲区溢出?

攻击者可以故意将精心制作的输入馈入程序,程序将尝试将该输入存储在不够大的缓冲区中,因此输入会覆盖连接到缓冲区空间的部分内存。如果程序的内存布局定义明确,则攻击者可以故意覆盖已知包含可执行代码的区域。然后,攻击者可以用自己的可执行代码替换这些代码,这可以大大改变程序的工作方式。

例如,如果内存中的被覆盖部分包含一个指针(指向内存中另一个位置的对象),则攻击者的代码可以用另一个指向漏洞利用有效载荷的指针来替换该代码。这样就可以将整个程序的控制权转移给攻击者的代码。

谁容易受到缓冲区溢出攻击?

某些编程语言比其他编程语言更容易发生缓冲区溢出。C 和 C++ 是两种脆弱性较高的热门语言,因为它们不包含内置的保护措施以防止访问或覆盖内存中的数据。Windows、Mac OSX 和 Linux 都包含用这两种语言编写的代码。

Java、PERL 和 C# 等更现代的语言具有内置特性,可帮助减少缓冲区溢出的机会,但不能完全阻止缓冲区溢出。

如何防范缓冲区溢出攻击

幸运的是,现代操作系统具有运行时保护,可帮助防护缓冲区溢出攻击。我们来探讨有助于防护漏洞利用风险的 2 种常见保护措施:

  • 地址空间随机化 - 随机重新排列进程的关键数据区的地址空间位置。缓冲区溢出攻击通常依赖于了解重要的可执行代码的确切位置,地址空间的随机化可以使这种了解几乎不可能。
  • 防止数据执行 - 标记内存的某些区域(可执行或不可执行),防止漏洞利用运行不可执行区域中的代码。

软件开发人员还可以通过使用内置保护的语言编写或在其代码中使用特殊的安全性程序,来预防缓冲区溢出漏洞。

尽管存在上述预防措施,但开发人员仍然发现了新的缓冲区溢出漏洞,有时是在遭遇成功的漏洞利用之后。发现新漏洞时,工程师需要修补受影响的软件,并确保该软件的用户可以获取补丁。

缓冲区溢出攻击有哪些类型?

缓冲区溢出攻击有很多类型,它们采用不同的策略并针对不同的代码段。以下是一些最著名的类型。

  • 堆栈溢出攻击 - 这是最常见的缓冲区溢出攻击类型,涉及到调用堆栈*上的缓冲区溢出。
  • 堆溢出攻击 - 这种类型的攻击针对开放的内存池中称为堆*的数据。
  • 整数溢出攻击 - 在整数溢出中,算术运算得出对于要存储结果的整数类型而言太大的整数;这可能导致缓冲区溢出。
  • Unicode 溢出 - Unicode 溢出通过将 Unicode 字符插入需要 ASCII 字符的输入中来创建缓冲区溢出。(ASCII 和 unicode 是使计算机表达文本的编码标准。例如,字母“a”由 ASCII 中的数字 97 表达。虽然 ASCII 码仅用于表达西方语言中的字符,但 unicode 可以为地球上几乎所有书面语言创建字符。因为 unicode 中有更多可用的字符,所以许多 unicode 字符大于最大的 ASCII 字符。)

*计算机依赖于两种不同的内存分配模型,称为堆栈和堆;两者都位于计算机的 RAM 中。堆栈结构整齐,并以“后进先出”的模型保存数据。最后放入堆栈中的任何数据都将首先发出,就像是插入弹夹中的最后一颗子弹将被首先发射一样。堆则是杂乱无章的额外内存池,数据不会以任何特定顺序进入或离开堆。由于从堆栈访问内存比从堆访问快得多,因此通常将堆保留为供较大的数据段或程序员想要显式管理的数据使用。