前面讲到了ROP攻击,我们了解到其主要是利用栈溢出进行漏洞攻击。栈溢出是缓冲区溢出的一部分,对于缓冲区溢出来讲,只有从更全面的视角了解它,才能更针对性的提出解决方案、构建安全防线。
C和C++是两种非常容易受到缓冲区溢出攻击的语言,因为它们没有内置的保护措施来防止覆盖或访问内存中的数据。攻击者可以通过覆盖应用程序的内存来利用缓冲区溢出漏洞,例如,攻击者可能会引入额外的代码,向应用程序发送新的指令以获得对IT系统的访问权。
缓冲区溢出攻击有很多类型,它们采用不同的策略并针对不同的代码段。
以下是一些最著名的类型。
- 堆栈溢出攻击 – 这是最常见的缓冲区溢出攻击类型,涉及到调用堆栈上的缓冲区溢出。
- 堆溢出攻击 – 这种类型的攻击针对开放的内存池中称为堆的数据。
- 整数溢出攻击 – 在整数溢出中,算术运算得出对于要存储结果的整数类型而言太大的整数,这可能导致缓冲区溢出。
- Unicode溢出– Unicode溢出通过将Unicode字符插入需要ASCII字符的输入中来创建缓冲区溢出。(ASCII和unicode 是使计算机表达文本的编码标准。例如,字母“a”由ASCII中的数字97表达。虽然ASCII码仅用于表达西方语言中的字符,但unicode可以为地球上几乎所有书面语言创建字符。因为unicode中有更多可用的字符,所以许多unicode字符大于最大的ASCII字符。)
一般来讲,攻击者可以故意将精心制作的输入馈入程序,程序将尝试将该输入存储在不够大的缓冲区中,因此输入会覆盖连接到缓冲区空间的部分内存。如果程序的内存布局定义明确,则攻击者可以故意覆盖已知包含可执行代码的区域。然后,攻击者可以用自己的可执行代码替换这些代码,这可以大大改变程序的工作方式。
例如,如果内存中的被覆盖部分包含一个指针(指向内存中另一个位置的对象),则攻击者的代码可以用另一个指向漏洞利用有效载荷的指针来替换该代码。这样就可以将整个程序的控制权转移给攻击者的代码。
计算机依赖于两种不同的内存分配模型,称为堆栈和堆;两者都位于计算机的RAM中。堆栈结构整齐,并以“后进先出”的模型保存数据。最后放入堆栈中的任何数据都将首先发出,就像是插入弹夹中的最后一颗子弹将被首先发射一样。堆则是杂乱无章的额外内存池,数据不会以任何特定顺序进入或离开堆。由于从堆栈访问内存比从堆访问快得多,因此通常将堆保留为供较大的数据段或程序员想要显式管理的数据使用。
当发生缓冲区溢出攻击时,通常会造成:
- 系统崩溃:缓冲区溢出攻击通常会导致系统崩溃。它还可能导致缺乏可用性和程序陷入无限循环。
- 访问控制丢失:缓冲区溢出攻击通常涉及使用任意代码,这通常超出程序安全策略的范围。
- 进一步的安全问题:当缓冲区溢出攻击导致任意代码执行时,攻击者可能会利用它来利用其他漏洞并破坏其他安全服务。
开发人员可以通过代码中的安全措施或使用提供内置保护的语言来防止缓冲区溢出漏洞。此外,现代操作系统具有运行时保护。三种常见的保护措施是:
地址空间随机化 (ASLR) -在数据区域的地址空间位置周围随机移动。通常,缓冲区溢出攻击需要知道可执行代码的位置,而随机化地址空间使得这几乎不可能实现。
数据执行预防-将内存的某些区域标记为不可执行或可执行,从而阻止攻击在不可执行区域中运行代码。
结构化异常处理程序覆盖保护 (SEHOP)-有助于阻止恶意代码攻击结构化异常处理 (SEH),这是一种用于管理硬件和软件异常的内置系统。因此,它可以防止攻击者利用SEH覆盖利用技术。在功能层面上,使用基于堆栈的缓冲区溢出来覆盖存储在线程堆栈上的异常注册记录来实现SEH覆盖。
代码和操作系统保护方面的安全措施还不够。当组织发现缓冲区溢出漏洞时,必须迅速做出反应,对受影响的软件进行修补,并确保软件用户可以访问补丁。而基于内存保护防御缓冲区溢出,可以第一时间发现并防御这类缓冲区溢出漏洞攻击。
安芯网盾的智能内存保护系统通过细粒度的监控内存读、写、执行行为,可实时检测内存中存在的堆喷射、堆栈溢出、内存数据覆盖、shellcode执行等异常行为,一旦检测这类异常行为,实时拦截并阻断漏洞利用过程,即使不安装补丁依然可以起到防护作用,从而解决系统本身脆弱性问题。
栈属性攻击:检测并拦截修改栈内存属性的行为(例如修改为可执行),防止恶意代码破坏内。
栈代码执行攻击:检测并拦截函数执行完成后,控制流返回到栈中的行为。
堆攻击:检测并拦截内存中分配多个对象并填充内存块为恶意代码的行为,防止堆溢出利堆攻击用、漏洞利用或破坏。
栈翻转:检测并拦截漏洞利用过程中,利用栈翻转达到在栈上构造rop链。对于缓冲区溢出,做好安全检测,才能更好的进行安全防御,避免威胁攻击带来的损失。