2012-04-11 36 views
4

这是一项任务,但我对基本理解存在问题。使用snprintf缓冲区溢出

漏洞代码:

int choc(char *arg) 
{ 
    char buf[400]; 
    snprintf(buf, sizeof buf, arg); 
    return 0; 
} 

据我所知,ARG必须是一个格式字符串将与我要执行的代码的地址覆盖返回地址。但是我在创建格式字符串时遇到了麻烦。该格式字符串需要

所以,事情有:

  1. 返回指令的地址,这是我需要覆盖
  2. %的名单X
  3. 的价值,我会写在返回地址。这将是我想要执行的代码的地址。

为了得到返回地址,我只需要在gdb中查看'ret'指令的地址吧? %x的目的究竟是什么?我如何编码我想要在格式字符串中执行的代码的地址?

我做了一个测试: 使用gdb我发现我的buf地址是0xbffffba0。我生成了arg为“\ xa0 \ xfb \ xff \ xbf_%x。%x。%n”;不应该这样写地址0xbffffba0处的buff的开始值吗?不过,我得到一个段错误。我究竟做错了什么?

任何帮助,将不胜感激!

+0

我不想写一个答案,但我只是做了这个任务。对于那些追随我的人,我通过逐字节地覆盖'__DTOR_END__'来实现它。你最终会使用几乎所有由snprintf调用分配给你的字节,但是你可以及时完成,并跳入'arg',它应该在你的shellcode结尾。我跟着这个链接的第一部分解释让我开始:https://www.exploit-db.com/docs/28476.pdf – 2017-11-19 05:55:55

回答

1

您尝试利用的漏洞称为格式字符串漏洞。 有关此主题的进一步调查,我会推荐THIS链接或书称为“黑客:利用艺术”。

+0

是的,我阅读了这个链接。我相信我正在按照它告诉我的方式去做。然而,而不是写入buff,我得到了段错误。不知道为什么 – Catie 2012-04-11 20:10:22

+1

嗯,我不确定,但你的问题可能与一些在较新版本的Linux内置的漏洞countermeasuers,如“非可执行堆栈” – div 2012-04-11 20:14:33

+0

@ Catie-有可能是你太过分了,导致'snprintf'访问堆栈末尾的内存。逐步完成装配层面的功能,你应该能够看到这是否是问题。 – bta 2012-04-11 20:23:09

0

从调试器中读取值通常是不够的。某些平台具有地址空间随机化安全功能,这些功能会导致特定对象的地址在程序调用之间有所不同。相反,您需要查找堆栈中返回地址的存储位置(相对于snprintf调用)并在那里覆盖它。这是非常特定于CPU的。你在开发什么平台?

使用调试程序,在程序集级别上遍历该函数的代码,并在遇到return命令之前检查堆栈。确保堆栈和返回地址看起来像你认为他们应该看起来。这应该让你知道问题出在哪里。此外,您可以尝试在return之前使用调试器手动修改堆栈,以验证您的目标位置实际上是返回地址。

-1

答案是否定的,你不只是需要'ret'指令的地址。你实际需要的是'ret'指令加载的内存位置。看看这张图:

http://post.queensu.ca/~trd/377/tut5/stack.html

你的目标是要覆盖“返回地址”。

我会继续尝试写一个简短的程序来显示这个指针(来)。

更新:我有个坏消息。我也弄不明白。我写过:

#include <stdio.h> 
#include <stdlib.h> 

void bar() 
{ 
    printf("Bar function\n"); 
} 

void foo() 
{ 
    void (**p)(void); 
    asm volatile("movl %%ebp, %0\n\t" : "=r"(p) : : "%0"); 
    p += 1; 
    *p = bar; 
} 

int main() 
{ 
    foo(); 
    return 0; 
} 

这会导致分段错误,而不打印bar()中的句子。我希望它能奏效......所以现在我和你一样困惑。任何人都可以解释为什么bar()不会在我的代码中执行?

+0

谢谢!那么返回地址是否保存在%eip中?在gdb中,我做了'info frame',并看到了%eip的保存地址,并创建了与上面相同的字符串,只是将该地址交换完毕。始终是赛格故障。我只是想让它在没有seg错误的情况下写入任何地方(这就是为什么选择buff的开始)。 – Catie 2012-04-11 21:41:59

2

"\xa0\xfb\xff\xbf"不应该是buf的地址,而应该是堆栈中返回地址的位置(这是您希望覆盖的值)。你必须使用gdb来找到这个值。

然后,您需要在格式字符串中放入足够的%x,以便%n从堆栈中读取该值并写入您指定的地址。您还需要使用正确的字段大小,以便%n实际上会写入正确的值。