缓冲区溢出攻击和 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 数据处理(例如 strcpy
或 strcat
)让恶意输入写入内存超出数组末尾。当数组分配在 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 堆栈内存而变得不可能。
我开始研究软件安全,但我很难理解什么是缓冲区溢出攻击和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 数据处理(例如 strcpy
或 strcat
)让恶意输入写入内存超出数组末尾。当数组分配在 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 togets()
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 堆栈内存而变得不可能。