【问题标题】:null terminator in the middle of a string字符串中间的空终止符
【发布时间】:2014-05-07 17:45:42
【问题描述】:

如果程序接收到一个中间带有空终止符的字符串作为 argv[1] 参数会发生什么?例如:

./program test'\0'example

argv[1] 的值是多少?是测试吗?是测试\ 0示例吗?我有这几行代码

max = sizeof(filename);
len = strlen(argv[1]);
if (len > max) goto error;
strcpy(filename, argv[1]);

我需要为这个程序构建一个漏洞利用,我想做的是让 argv[1] 值得测试'\0'示例,所以 strlen(argv[1])=strlen("test")=4 和strcpy(filename, argv[1])=strcpy(filename, "test") 所以我可以使用字符串的其余部分(示例部分)来放置我的漏洞利用。是否可以?非常感谢?

【问题讨论】:

  • strlenstrcpy 都停在一个空字符上,所以不会有什么不同。无论如何,该输入看起来不会输入空字符。
  • 我很怀疑大多数 shell 甚至会传递空字符以外的任何内容。
  • 提示:想想一个长度为n 的字符串需要多少字节。
  • 我不认为这是一个空字符:echo test'\0'example -> test\0example...
  • 这是,至少在 bash 中:echo test$'\000'example

标签: c string terminator


【解决方案1】:

argv[1]char* 类型的指针。它的值是一个地址,而不是一个字符串。具体来说,它的值为char对象的地址,其值为't'

C 标准(在第 7.1.1 节中)具有以下定义:

string 是一个连续的字符序列,以第一个 null 结尾,包括第一个 null 性格。
[...]
指向字符串的指针 是指向其初始(最低地址)字符的指针。 字符串的长度是空字符之前的字节数,并且 字符串的值是包含的字符的值的顺序,按顺序排列。

由于argv[1] 指向连续字符序列的第一个字符,其中一个是空字符,它是一个指向字符串的指针。该字符串的值为“test”(包括终止符'\0'),字符串长度为4。

通常说argv[1] 的值是"test",作为一种口头速记,但这并不精确 -- *es

argv[1] 也指向一个array 字符的第一个字符。该数组的前 5 个字节包含字符串 "test"。整个数组包含字符值:

{ 't', 'e', 's', 't',
  '\0',
  'e', 'x', 'a', 'm', 'p', 'l', 'e',
  '\0' }

如果您将argv[1] 的值传递给字符串函数,该函数将只能看到"test",并且不会访问终止'\0' 之后的任何内容。数组的其余内容仍然完全有效,并且可以使用不仅仅对字符串进行操作的函数(如 memcpy)进行访问。

作为一种口头速记,通常说argv[1] 的值是"test",但这并不精确——尤其是在这种情况下字符串的值和包含该字符串的数组的值是重要的。

是否可以以argv[1] 指向具有这些特定内容的数组的第一个元素的方式调用您的主程序是另一回事,这取决于您的操作系统。

【讨论】:

    【解决方案2】:

    argv[1] 的值将是 "test",假设您实际上设法在终端上获得了一个真正的 NULL 字符,而不仅仅是文字字符 \0

    正如 RedAlert 的评论所提到的,strlenstrcpy 都停止在空字符上,因此获取空字符对大多数攻击没有帮助。

    您很可能需要找到一种不使用字符 \0 的方法来执行漏洞利用。

    【讨论】:

      【解决方案3】:

      当从main() 内部调用main() 时,您的想法有效

      #include <stdio.h>
      
      int main(int argc, char **argv) {
        if (argc == 1) {
          char *data[] = {"", "5one\0two", "7three\0four", "6five\0six"};
          main(4, data); // call main again, with exploitable data
        } else {
          if (!argv[0][0]) { // test for empty argv[0]
            for (int i = 1; i < 4; i++) {
              printf("%s ==> %s\n", argv[i] + 1, argv[i] + argv[i][0] - '0');
            }
          }
        }
        return 0;
      }
      

      我不确定当从 C 库初始化代码中调用 main() 时它是否会起作用......或者即使你可以让你的 shell 接受 NUL 字符作为参数的一部分。

      【讨论】:

        猜你喜欢
        • 2012-01-02
        • 2011-06-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-07
        • 2021-06-12
        • 2020-10-24
        • 2021-11-28
        相关资源
        最近更新 更多