缓冲区是内存存储区域,在数据从一个位置传输到另一个位置时临时保存数据。当数据量超过内存缓冲区的存储容量时,就会发生缓冲区溢出(或buffer overrun)。结果,试图将数据写入缓冲区的程序会覆盖相邻的内存位置。
例如,用于登录凭据的缓冲区可能设计为期望 8 字节的用户名和密码输入,因此如果交易涉及 10 字节的输入(即比预期多 2 字节),程序可能会写入多余的部分超过缓冲区边界的数据。
缓冲区溢出会影响所有类型的软件。它们通常是由于格式错误的输入或未能为缓冲区分配足够的空间造成的。如果事务覆盖可执行代码,它可能导致程序行为不可预测并生成不正确的结果、内存访问错误或崩溃。
攻击者通过覆盖应用程序的内存来利用缓冲区溢出问题。这会改变程序的执行路径,触发破坏文件或暴露隐私信息的响应。例如,攻击者可能会引入额外代码,向应用程序发送新指令以获得对 IT 系统的访问权限。
如果攻击者知道程序的内存布局,他们可以故意提供缓冲区无法存储的输入,并覆盖包含可执行代码的区域,将其替换为他们自己的代码。例如,攻击者可以覆盖指针(指向内存中另一个区域的对象)并将其指向漏洞利用负载,从而获得对程序的控制权。
缓冲区溢出攻击的类型
基于堆栈的缓冲区溢出更为常见,并且利用仅在函数执行期间存在的堆栈内存。基于堆的攻击更难实施,并且涉及淹没分配给程序的内存空间,超出当前运行时操作使用的内存。
哪些编程语言更容易受到攻击?
C 和 C++ 是两种极易受到缓冲区溢出攻击的语言,因为它们没有内置的保护措施来防止覆盖或访问内存中的数据。Mac OSX、Windows 和 Linux 都使用用 C 和 C++ 编写的代码。PERL、Java、JavaScript 和 C# 等语言使用内置的安全机制来最大限度地减少缓冲区溢出的可能性。
如何防止缓冲区溢出
开发人员可以通过代码中的安全措施或使用提供内置保护的语言来防止缓冲区溢出漏洞。
此外,现代操作系统具有运行时保护。三种常见的保护是:
- 地址空间随机化 (ASLR) — 在数据区域的地址空间位置周围随机移动。通常,缓冲区溢出攻击需要知道可执行代码的位置,而随机化地址空间使这几乎不可能。
- 数据执行预防 — 将内存的某些区域标记为不可执行或可执行,从而阻止在不可执行区域运行代码的攻击。
- 结构化异常处理程序覆盖保护 (SEHOP) — 有助于阻止恶意代码攻击结构化异常处理 (SEH),这是一个用于管理硬件和软件异常的内置系统。因此,它可以防止攻击者利用 SEH 覆盖利用技术。在功能层面,SEH 覆盖是通过使用基于堆栈的缓冲区溢出来覆盖存储在线程堆栈中的异常注册记录来实现的。
代码和操作系统保护方面的安全措施还不够。当组织发现缓冲区溢出漏洞时,它必须迅速做出反应,为受影响的软件打补丁,并确保软件的用户可以访问补丁。