【发布时间】:2017-05-08 07:08:07
【问题描述】:
我正在使用此源代码了解缓冲区溢出:
#include <stdio.h>
int main()
{
char buf[16];
gets(buf);
printf("buf @ %8p\n", (void*)&buf);
return 0;
}
我尝试将 Null 字符 ('\0') 写入 buf 变量。
首先,在 gdb 中,我在第 6 行,在 gets() 函数之后设置断点并使用 r <<< $(python -c 'print "\0"*11 + "AAAA"') 运行它
当我探索堆栈时,我意识到它只会将“AAAA”写入buf。会发生什么?
(gdb) x/16xw &buf
0xffffcf80: 0x41414141 0xffffd000 0xffffd04c 0x080484a1
0xffffcf90: 0xf7fb43dc 0xffffcfb0 0x00000000 0xf7e1a637
0xffffcfa0: 0xf7fb4000 0xf7fb4000 0x00000000 0xf7e1a637
0xffffcfb0: 0x00000001 0xffffd044 0xffffd04c 0x00000000
但是,当我使用r <<< $(python -c 'print "\1"*11 + "AAAA"') 运行程序时,buf 将是:
(gdb) x/16xw &buf
0xffffcf80: 0x01010101 0x01010101 0x41010101 0x00414141
0xffffcf90: 0xf7fb43dc 0xffffcfb0 0x00000000 0xf7e1a637
0xffffcfa0: 0xf7fb4000 0xf7fb4000 0x00000000 0xf7e1a637
0xffffcfb0: 0x00000001 0xffffd044 0xffffd04c 0x00000000
所以
gets()函数不会接收到Null字符或者stdin会忽略它?
P/S:我在 gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609 上使用gcc -m32 -fno-stack-protector -g stack.c -o stack 构建它。
更新:经过一些建议,我试试这个:
#include <stdio.h>
int main()
{
char buf[16];
gets(buf);
printf("buf @ %8p\n", (void*)&buf);
for (int i = 0; i < 16; ++i) // this is for loop all the buf
{
printf("%02x ", buf[i]);
}
return 0;
}
它适用于 '\0'
$ gcc -g j_stack.c -o j_stack
$ python -c 'print "AAAA" + "\0"*6 + "AAAA"'| ./j_stack
buf @ 0xffffcfbc
41 41 41 41 00 00 00 00 00 00 41 41 41 41 00 ffffffff
但是如何在
gdb程序中提供包含'\0'到buf的输入
【问题讨论】:
-
小提示:如果您将
buf初始化为所有 0xFF 或类似的东西,阅读此输出会更容易 -
gets和fgets函数不特别对待'\0'。他们可以很好地读取空字符。我使用您的程序读取了字符串"ab\0c\n",它按预期工作。 -
我认为这是由于您使用“这里的字符串”来提供输入(
<<<)。这是将输入传递给程序的一种非常复杂的方式,你不觉得吗?将 gdb 排除在外,只使用 shell 中的标准管道;然后你应该看到它工作。让我们知道这是否属实并因此值得回答。 -
抱歉...我的记忆是用
\0代替\n。答案已删除。 -
运行:
od -c <<< $(python -c 'print "\0"*11 + "AAAA"');我得到的输出是四个 A 和一个换行符。经诊断,问题出在 Bash heredoc 处理中,而不是您的程序或gets()。当然,除了测试溢出,你应该知道gets()is too dangerous to be used — ever!。 (你仍然可以使用fgets();你可以简单地写fgets(buf, 4096, stdin);,就像buf一样大。)
标签: c gcc buffer-overflow