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

时间:2019-04-13 11:48:32

标签: c buffer-overflow

我开始修补缓冲区溢出,并编写了以下程序:

#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_address用地址f覆盖了g的返回地址,这将打开一个外壳。但是,如果将返回地址设置为instructions,则会遇到分段错误,并且instructions中的任何指令都不会执行。

我使用-fno-stack-protector在GCC上进行编译。

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

1 个答案:

答案 0 :(得分: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)上的说明是否可以在您的系统上进行编译。