首页 > 解决方案 > 需要帮助了解这个简短的 C++ 程序及其漏洞

问题描述

如果有人可以准确地向我解释代码的作用,我会很高兴。我知道存在缓冲区溢出和 bash 命令执行漏洞——但由于我是网络人而不是程序员,我真的可以使用一些帮助来理解整个代码。提前致谢!

int main () {
    int status;
    char t[1024]="ps -eo lstart,cmd | grep ";
    cout << "Content-type:text/html\r\n\r\n"<<endl;
    char *value = getenv("QUERY_STRING");
    strcat(t,value);
    status = system(strcat(t," | grep -v grep | head -n 1 | awk '{ print $1\" \"$3\" \"$2\" \"$5\" \"$4}'"));

    return 0;
}

标签: c++linuxsecuritybuffer-overflowcommand-execution

解决方案


tl;博士:这就是你的代码所做的,作为一个 shell 脚本:

#!/bin/bash
echo -en "Content-type:text/html\r\n\r\n"
ps -eo lstart,cmd | grep init | grep -v $QUERY_STRING | \
head -n 1 | awk '{ print $1" "$3" "$2" "$5" "$4}'

现在是更长的答案。

重写代码

首先,让我们通过一些错误处理将它变成 C++ 而不是 C(就像您的标签建议您询问的那样),然后谈谈发生了什么:

#include <iostream>
#include <string>
#include <string_view>

int main () {
    auto query_string = getenv("QUERY_STRING");
    if (query_string == nullptr) {
        std::cerr << "Couldn't obtain QUERY_STRING environment variable\n";
        return EXIT_FAILURE;
    }
    if (std::string_view{query_string}.empty()) {
        std::cerr << "Empty query string (QUERY_STRING environment variable)\n";
        return EXIT_FAILURE;
    }
    std::stringstream command_line;
    command_line 
        << "ps -eo lstart,cmd | grep "
        << query_string 
        << " | grep -v grep | head -n 1 | awk '{ print $1\" \"$3\" \"$2\" \"$5\" \"$4}'";
    std::cout << "Content-type:text/html\r\n\r\n";
    return system(command_line.str()); // security vulnerability, see below
}

我们在这里做什么?

因此,我们在这里创建一个命令行,然后使用该system()函数执行该命令行。它是使用一些开关调用ps命令,然后使用 , 进行一些文本处理grephead以及awk- 使用管道机制将每个命令的输出移动到下一个命令。它们的关键部分是我们使用环境变量QUERY_STRING来过滤ps结果,即我们列出匹配某个短语的进程。如果我们编译这个程序,设置环境变量并运行,它是这样的:

$ export QUERY_STRING=init
$ ./the_program
Content-type:text/html


Sun 3 Jun 2018 21:48:56

这给我们的是命令行不包含短语“init”的第一个进程的开始时间。所以现在你可以猜到我的系统从昨天开始就已经启动了......

最后,作为一个网络人,您可能意识到“内容类型”mumbo-jumbo 并且双换行符是一个 MIME 标头,因此此输出可能旨在用作 HTTP 响应。这可能是为了作为某种 CGI 脚本。

安全漏洞

  1. 在原始代码中,缓冲区大小被任意限制为 1024 - 而没有什么限制 QUERY_SIZE 不超过此值。如果它更长,您将有内存损坏,这可能会产生安全隐患;并且攻击者可能能够弄清楚您的内存布局,因此更加危险。这在 C++ 版本中消失了。
  2. 第二个漏洞与system命令有关。我们将任意字符串注入到我们正在创建的字符串中;并且没有什么可以阻止某人设置

    $export QUERY_STRING="dummy; rm -rf $HOME ; echo"
    

    在这种情况下,您将运行:

    ps -eo lstart,cmd | grep dummy; rm -rf $HOME ; echo | grep -v init | head -n 1 | awk '{ print $1" "$3" "$2" "$5" "$4}'
    

    这将删除有效用户主目录下的所有内容。或者它可以是任何命令,包括编译自定义 C/C++ 程序以在您的系统上运行一些任意代码。很坏。

  3. 即使您将 QUERY_STRING 清理为仅是一个有效的 grep 模式,如果有人以某种方式提供复杂的超长 grep 模式,仍然可能存在拒绝服务攻击。所以限制长度也是一个好主意。

推荐阅读