#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;
}
我正在使用堆栈粉碎保护功能编译该程序:
$ gcc -fstack-protector smash.c -o smash
这是我在执行过程中得到的内容:
$ ./smash 01234567890
01234567890v?\??nr?!??U
*** stack smashing detected ***: <unknown> terminated
保护工作正常,但我不明白为什么我看到的不是
argv[0]
。#1 楼
似乎您正在覆盖argv
数组本身,因此错误处理程序无法检索argv[0]
值。 #2 楼
实际上,这是一种相当新的缓解机制,旨在避免泄漏有关崩溃的应用程序堆栈的信息。您看到的“
<unknown>
”(由-fstack-protector
添加的静态字符串)是以前argv[0]
。但是,一些攻击者开始利用这一事实,即您可能会使堆栈溢出,到达argv[0]
并用您选择的地址覆盖它。实际上,如果可以控制argv[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_ABORT
时才调用do_backtrace
。添加了__fortify_fail_abort
以避免来自__stack_chk_fail
的回溯。我希望提供更多关于该缺陷的英文参考文献和文章,但似乎没人写过这个东西。不好意思
这是一篇用法语解释的文章:
堆栈粉碎保护器:fuite d'informations
#3 楼
strlen
返回字符串的长度,不包括结尾的NULL
字符,因此,memcpy
仅复制提供的字符,但末尾没有0
。 printf
将打印得到的所有内容,直到遇到NULL
为止,并因此打印这些“随机”字符。评论
我了解,但这不是我的问题。我的问题在第二行:
–Bob5421
19年11月3日在8:27
请将此澄清添加到您的问题中,因为“我不明白为什么我看到而不是argv [0]”尚不清楚。
–bart1e
19年11月3日在12:05
抱歉,stackexchange认为
–Bob5421
19年11月3日,12:26
评论
嗯,我真的很不高兴未能找到引用......唯一的好参考,我发现是法语。因此,如果有人可以提供很好的参考或链接(以可理解的语言),请随时在评论中提出建议。我将编辑答案以将其集成。
–恐怖
19/12/6在8:26