堆栈粉碎保护错误消息

逆向工程 部件 堆栈保护器
2021-06-10 08:26:17

这是一个非常丑陋的 C 程序:

 #include <stdio.h>
 #include <string.h>
 int main(int argc, char *argv[])
 {
    char buffer[10];
    memcpy(buffer,argv[1],strlen(argv[1]));
    printf("%s\n", buffer);
    return 0;
 }

我正在用 Stack-Smashing Protection 编译这个程序:

 $ gcc -fstack-protector smash.c -o smash

这是我在执行过程中得到的:

 $ ./smash 01234567890
 01234567890v?\??nr?!??U
 *** stack smashing detected ***: <unknown> terminated

保护工作正常,但我不明白为什么我看到的是 unknown 而不是argv[0].

3个回答

您似乎正在覆盖argv数组本身,因此错误处理程序无法检索该argv[0]值。

事实上,这是一种相当新的缓解机制,旨在避免泄漏有关崩溃应用程序堆栈的信息。

您看到的“ <unknown>”(这是由 加入的静态字符串-fstack-protector)以前是argv[0]. 但是,一些攻击者开始利用您可以溢出堆栈的事实,到达argv[0]并使用您选择的地址覆盖它。实际上,如果您可以控制地址 atargv[0]并使应用程序崩溃,则可以将整个堆栈泄漏到应用程序之外。

该技术主要用于fork()用于重新生成实例的服务器正如fork()克隆初始进程的内存一样,ASLR 是无用的,因为使用了相同的起始内存映像,然后一次又一次地使用相同的内存映射。

如果堆栈中存储了密钥或某些机密数据,则攻击者可以通过此功能访问它。

这就是为什么在去年的某个时候,一些开发人员决定argv[0]在显示有关堆栈粉碎的信息时避免使用<unknown>.

这是Unix/Linux Stack-Exchange 站点上的一个答案,它指出了glibc对此负责的代码部分

void
__attribute__ ((noreturn))
__fortify_fail_abort (_Bool need_backtrace, const char *msg)
{
  /* The loop is added only to keep gcc happy.  Don't pass down
     __libc_argv[0] if we aren't doing backtrace since __libc_argv[0]
     may point to the corrupted stack.  */
  while (1)
    __libc_message (need_backtrace ? (do_abort | do_backtrace) : do_abort,
            "*** %s ***: %s terminated\n",
            msg,
            (need_backtrace && __libc_argv[0] != NULL
             ? __libc_argv[0] : "<unknown>"));
}

并且,这是介绍补丁的原始提交的注释:

避免来自__stack_chk_fail[BZ #12189] 的回溯

__stack_chk_fail在损坏的堆栈上调用。堆栈回溯对于损坏的堆栈非常不可靠。__libc_message更改为仅当操作包括 时 接受 enum __libc_message_action并调用添加是为了避免从 .BEFORE_ABORTdo_backtrace__fortify_fail_abort__stack_chk_fail

我本来想提供更多关于这个缺陷的英文参考资料和文章,但似乎没有人写过这件事......对不起。

这是一篇解释它的文章(法语):

strlen返回不包括终止NULL字符的字符串的长度,因此memcpy只复制提供的字符而没有0结尾。

printf将打印它得到的所有内容,直到遇到NULL这些“随机”字符。