【问题标题】:Input zero bytes to C program via argv通过 argv 向 C 程序输入零字节
【发布时间】:2015-03-21 17:57:44
【问题描述】:

这是简单的 C 程序

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

int main(int argc, char **argv)
{
        int hex;
        memcpy(&hex, argv[1], 4);
        printf("hex %x\n", hex);
        return 0;
}

我做了以下实验

./main `python -c 'print "\x01\x01\x02\x01"'`

输出是可预测的:hex 1020101

接下来我尝试在输入中放入一些零字节

./main `python -c 'print "\x01\x00\x02\x01"'`

输出让我感到惊讶

hex 10201

然后我检查了 python 究竟输出到主输入的内容:

python -c 'print "\x01\x00\x02\x01"' > test
hexdump -C test

00000000  01 00 02 01 0a                                    |.....|
00000005

看来python老老实实把\x01\x00\x02\x01放到文件中并打印行尾符号。 我的理解是 argv[1] 应该是一个指针,指向放置字节模式 01000201 的内存。在这种情况下,输出应该是 1020001 而不是 10201。

问题 - 零字节在哪里?

【问题讨论】:

  • 通过使用反引号将参数传递给 shell。所以零字节永远不会被传递,因为\0 是字符串终止符。所以你基本上是在访问未初始化的内存。

标签: python c security memory argv


【解决方案1】:

零字节是字符串终止符,因此在使用反引号时它永远不会被 shell 传递。我很确定内核也不会在第一个零之后传递任何字节,因为它应该如何知道要复制的参数的实际长度?

您可以通过以下方式轻松验证这一点

echo `python -c 'print "\x01\x00\x02\x01"'` | hd

在您的程序中,您访问的是未初始化的内存,因为所有定义的第一个参数都在第一个 '\0' 之后结束。结果可能是确定性的,但本质上是未定义的。

【讨论】:

  • 当我尝试时,输出是01 02 01 0a
  • 所以在这种情况下,它只会吞下\0。尽管如此,它并没有改变参数字符串中不能有零字节的事实......
  • 我认为 shell 不会执行零字节的特殊操作。基本上我的错是我使用'hexdump -C test'来验证输入,但shell实际传输的是'cat test'。由于零字节不可打印,它们已经消失了。
  • 我什至在考虑编码问题,因为 python 的 print 在写入 stdout 时会采用控制台的默认编码。但这实际上只是未定义的行为。
猜你喜欢
  • 1970-01-01
  • 2019-10-12
  • 1970-01-01
  • 1970-01-01
  • 2014-03-17
  • 1970-01-01
  • 2013-10-08
  • 1970-01-01
  • 2015-03-11
相关资源
最近更新 更多