我开始修补缓冲区溢出,并编写了以下程序:
#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上进行编译。
如何防止这种分段错误的发生?
答案 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)
上的说明是否可以在您的系统上进行编译。