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

What is the difference between a buffer overflow attack and a ROP attack?

我开始研究软件安全,但我很难理解什么是缓冲区溢出攻击和ROP攻击。

据我了解,

缓冲区溢出攻击:

When a buffer has a certain size, fill the buffer and an add additional code so that the attacker can execute another function in the code or his/her own shellcode.

ROP 攻击:

Give a certain input which can override the return address, so that the attacker can control the flow.

但这两者之间的确切区别是什么?

我觉得两者都只是提供了过多的输入来覆盖不应接近的区域。

例如,如果我有一个代码

  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攻击还是缓冲区溢出攻击?

ROP 攻击是一种您可以通过 buffer-overflow 漏洞传递的有效负载,用于堆栈上的缓冲区。(溢出其他缓冲区可能会让您覆盖其他缓冲区数据,例如在结构或附近的其他全局变量中,但不控制 program-counter。)


缓冲区溢出是指不正确的边界检查或 implicit-length 数据处理(例如 strcpystrcat)让恶意输入写入内存超出数组末尾。当数组分配在 call-stack 上时,这会变得很有趣,因此它后面的内容之一是此函数的 return 地址。

(理论上,覆盖静态数组末尾的静态变量可能是一种有用的漏洞,这也是缓冲区溢出。但通常缓冲区溢出意味着堆栈上有缓冲区,允许攻击者来控制 return 地址。从而获得对指令指针的控制。)

除了新的 return 地址外,您的恶意数据还将包含更多数据,这些数据将位于内存中 return 地址的下方和上方。其中一部分是 有效负载 。仅控制 return 地址通常是不够的:在大多数进程中,没有任何地方可以跳转到该地址(没有其他输入)将 execve 一个 shell 侦听 TCP 端口,例如。

传统上,您的有效负载将是 machine-code(shell代码),而 return 地址将是您知道有效负载将着陆的堆栈地址。 (+- NOP 幻灯片,因此您不必完全正确)。

堆栈 ASLR 和 non-executable 堆栈使得传统的 shell 代码注入方法无法在普通的现代程序中利用缓冲区溢出。 “缓冲区溢出攻击”过去(我认为)暗示shell代码注入,因为没有必要寻找更复杂的攻击。但这不再是事实。


ROP 攻击是指负载是 return 地址序列 pop 指令弹出的数据,and/or一些字符串,如 "/bin/sh"。有效负载中的 first return 地址将执行发送到可执行页面中已知地址处的某些 already-existing 字节。


and try to execute the function check() by giving a certain input to gets() function.

check()的代码已经存在于目标程序中,所以最简单的攻击就是ROP攻击。

这是绝对最简单的 ROP 攻击形式,其中执行您想要执行的操作的代码存在于单个已知地址中,不需要任何“函数参数”。所以它是一个很好的例子来介绍这个话题。

Is this a ROP attack or a buffer overflow attack?

两者都是。注入 ROP payload 是缓冲区溢出。

如果程序是用-z execstack -no-pie编译的,你也可以选择注入,例如x86 shell执行 mov eax, imm32 / jmp eax 跳转到 check 的已知绝对地址的代码。在那种情况下,这将是缓冲区溢出而不是 ROP 攻击;这将是一次 code-injection 攻击。

(您可能不会称它为“shell代码”,因为目的不是 运行 一个 shell 替换程序,而是使用现有代码做一些事情的 程序。但是术语经常被草率地使用,所以我想很多人会把任何可注入的机器代码称为“shell代码”,不管它做什么。)


Buffer overflow attack:

When a buffer has a certain size, fill the buffer and an add additional code so that the attacker can execute another function in the code or his/her own shellcode.

“在代码中”选项将是 ROP 攻击。您将 return 地址指向已在内存中的代码。

“或 his/her 自己的 shellcode”选项将是 code-injection 攻击。您将 return 地址指向刚刚溢出的缓冲区。 (直接或通过 ret2reg ROP 攻击来击败堆栈 ASLR,例如通过在 x86 上寻找 jmp esp 小工具。)

这个“缓冲区溢出”的定义仍然有点太狭窄了:它排除了覆盖一些其他关键变量(如 bool user_authenticated而不 覆盖 return地址。

但是,是的,代码注入和 ROP 攻击是两种主要方式,代码注入通常因 non-executable 堆栈内存而变得不可能。