如何利用缓冲区溢出在堆栈上执行指令

4

我开始 tinkering 超出缓冲区,编写以下程序:

#include <unistd.h>

void g() {
  execve("/bin/sh", NULL, NULL);
}

void f() {
  long *return_address;
  char instructions[] = "\xb8\x01\x00\x00\x00\xcd\x80"; // exit(1)

  return_address = (long*) (&return_address + 2);
  *return_address = (long)&g; // or (long)instructions
}

int main() {
  f();
}

它做了我期望的事情: return_addressg 的地址覆盖了 f 的返回地址,从而打开了一个 shell。但是,如果我将返回地址设置为 instructions,就会出现分段错误,并且 instructions 中的指令都不会被执行。

我使用 GCC 进行编译,使用 -fno-stack-protector

我该如何防止这种分段错误的发生?


3
我不是专家,但是可能是因为“指令”(instructions)保存在数据段中,因此触发了数据执行保护(或在Linux下的名称),导致程序被终止。如果我理解正确,这与堆栈溢出不同,并且它不会被“-fno-stack-protector”禁用。但我并不确定! - Fabio says Reinstate Monica
@FabioTurati,“指令”已经存储在堆栈中,我已通过GDB进行了检查。 - Spirine
1个回答

2

至少有一个问题与缓冲区溢出无关。

execve("/bin/sh", NULL, NULL);

第一个NULL成为你启动的进程的argv。argv必须是以NULL结尾的字符串数组。因此,当/bin/sh启动时,尝试读取argv [0]并解引用NULL时可能会发生段错误。

"最初的回答"的意思是上面这段话的原始回答。

void g(void) {
    char *argv[] = { "/bin/sh", NULL };
    execve(argv[0], argv, NULL);
}

您可以在gcc命令行中添加-z execstack,这将告诉链接器允许可执行堆栈。您还应该验证您那里的指令是否是来自某个教程中exit(1)编译成的代码。"最初的回答"

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