缓冲区溢出攻击和ROP攻击有什么区别?

5
我开始学习软件安全,但我不理解什么是缓冲区溢出攻击和ROP攻击。
据我所知,
缓冲区溢出攻击: 当一个缓冲区到达其大小限制时,填充缓冲区并添加其他代码,以便攻击者可以执行代码中的另一个函数或自己的shellcode。
ROP攻击: 通过给定某些输入,可以覆盖返回地址,从而使攻击者可以控制代码流程。
但是这两种攻击的确切区别是什么?
我觉得它们都只是提供了过多的输入来覆盖不应被访问的区域。
例如,如果我有以下代码:
  1 #include <stdio.h>
  2 
  3 void check(){
  4     printf("overflow occurs!\n");
  5 }
  6 
  7 int main(int argc, char* argv[]){
  8     char buffer[256];
  9     gets(buffer);
 10     printf("%s\n", buffer);
 11     return 0;
 12 }

尝试通过向gets()函数提供某个输入来执行check()函数。

这是一次ROP攻击还是缓冲区溢出攻击?


1
缓冲区溢出:通过在缓冲区外部写入一些有效载荷,通常是shellcode,来进行注入。ROP:通过注入已存在于目标程序中的代码块地址(“gadgets”)来进行注入。请注意,ROP在技术上也是一种缓冲区溢出攻击。 - Jester
3
似乎不同的开发人员对于“缓冲区溢出攻击”这个术语的理解有所不同。我理解这个术语是指ROP攻击是缓冲区溢出攻击的一种特殊变体。 - Martin Rosenau
2
你可以说缓冲区溢出是一种“传递方式”,而ROP则是一种特定类型的有效载荷。 - Jester
1
@Jester:我同意Martin的观点:缓冲区溢出通常是攻击者控制调用堆栈上返回地址的一种方式。(溢出其他缓冲区通常不那么有趣)。包含机器代码有效载荷完全是可选的,现在不再暗示它是缓冲区溢出的唯一事情。特别是因为大多数正常系统由于非可执行堆栈而免疫标准shellcode注入。哦,我想这个评论实际上回答了问题 >.< - Peter Cordes
1个回答

7
一种ROP攻击是通过堆栈缓冲区溢出漏洞向负载交付的方式之一。(溢出其他缓冲区可能会让你覆盖其他数据,例如在结构体或附近的其他全局变量中,但无法控制程序计数器。)
缓冲区溢出是指不正确的边界检查或隐式长度数据处理(例如strcpy或strcat)允许恶意输入将内存写入数组末尾以外。当该数组在调用堆栈上分配时,情况会变得有趣,因此以下内容之一是此函数的返回地址。
(理论上,超出静态数组末尾的静态变量也可能是利用漏洞的有效方法,这也是缓冲区溢出。但通常缓冲区溢出意味着堆栈上的缓冲区,使攻击者能够控制返回地址。从而获得对指令指针的控制。)
除了新的返回地址,您的恶意数据还包括位于该返回地址下方和上方的内存中的更多数据。其中一部分是有效载荷。仅控制返回地址通常是不够的:在大多数进程中,没有任何地方可以跳转到,例如(没有其他输入)将execve监听TCP端口的shell。
传统上,您的有效载荷将是机器代码(“shellcode”),而返回地址将是您知道该有效载荷会降落的堆栈地址。 (+- NOP滑动,因此您不必完全正确)。
堆栈ASLR和非可执行堆栈使传统的shellcode注入方法在正常现代程序中利用缓冲区溢出变得不可能。 "缓冲区溢出攻击"曾经(我想)意味着shellcode注入,因为没有必要寻找更复杂的攻击方式。但这已经不再是真的了。
ROP攻击是一种有效载荷是一系列返回地址以及由pop指令弹出的数据和/或像"/bin/sh"这样的某些字符串的情况。有效负载中的第一个返回地址将执行到已知地址中可执行页面中的一些已存在字节。
并尝试通过向gets()函数提供某些输入来执行check()函数的代码已经存在于目标程序中,因此最简单的攻击将是ROP攻击。
这是ROP攻击的绝对简单形式,其中执行确切操作所需的代码存在于单个已知地址,无需任何“函数参数”。因此,它可以很好地介绍这个主题。
它既是ROP攻击也是缓冲区溢出攻击。通过缓冲区溢出来注入ROP有效载荷。
如果程序使用-z execstack -no-pie编译,您还可以选择注入例如x86 shellcode,执行mov eax, imm32 / jmp eax以跳转到check已知的绝对地址。在这种情况下,它将是缓冲区溢出而不是ROP攻击; 这将是代码注入攻击。
(您可能不会称其为“shellcode”,因为目的不是以程序替换shell运行,而是使用现有代码执行某些操作。但术语通常使用不严谨,因此我认为许多人无论它做什么都会将可注入机器代码称为“shellcode”。)
缓冲区溢出攻击: 当缓冲区具有一定大小时,请填充缓冲区并添加其他代码,以使攻击者可以在代码中执行另一个函数或自己的shellcode。
“在代码中”选项将是ROP攻击。 您可以将返回地址指向内存中已经存在的代码。
“或者他/她自己的shellcode”选项将是代码注入攻击。您可以将返回地址指向刚刚溢出的缓冲区。(直接或通过ret2reg ROP攻击,以查找x86上的jmp esp小工具来打败堆栈ASLR)。
这个“缓冲区溢出”定义仍然稍微有些狭窄:它排除了覆盖其他关键变量(例如bool user_authenticated )而不覆盖返回地址的情况。
但是,代码注入和ROP攻击是两种主要方法,其中由于非可执行堆栈内存而使代码注入通常变得不可能。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接