需要帮助了解这个简短的C++程序及其漏洞

需要帮助了解这个简短的C++程序及其漏洞,c++,linux,security,buffer-overflow,command-execution,C++,Linux,Security,Buffer Overflow,Command Execution,如果有人能准确地向我解释代码的作用,我会很高兴的。我知道存在缓冲区溢出和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 = gete

如果有人能准确地向我解释代码的作用,我会很高兴的。我知道存在缓冲区溢出和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;
}

这只是声明变量状态

这声明了t,带有C字符串ps-eo lstart,cmd | grep。 对于字符串,t的最大容量为1024字节,对于\0,容量为1023+1字节

打印下面的字符串

cout << "Content-type:text/html\r\n\r\n"<<endl;
将上面的值连接到t。这里可能会出现缓冲区溢出,因为您不知道值中字符串的大小,它可能超过1024字节

strcat(t,value);
调用系统函数,用所有这些grep,etc,etc命令连接上一个t。。。这里您可能会有另一个缓冲区溢出,一旦t也会溢出它的1024字节

status = system(strcat(t," | grep -v grep | head -n 1 | awk '{ print $1\" \"$3\" \"$2\" \"$5\" \"$4}'"));
tl;dr:这就是您的代码作为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
}
这为我们提供了第一个进程的开始时间,该进程的命令行不包含短语init。所以现在你可以猜到我的系统从昨天起就启动了

最后,作为一名网络人员,您可能会意识到内容类型mumbo jumbo,而双换行符是一个MIME头,因此此输出可能会用作HTTP响应。可能这是一种CGI脚本

安全漏洞 在最初的代码中,缓冲区大小被任意限制为1024,而没有任何东西限制查询大小不超过1024。如果时间更长,内存就会损坏,这可能会带来安全隐患;而且攻击者很可能能够找出您的内存布局,因此这更危险。这是用C++版本的。 第二个漏洞与系统命令有关。我们在创建的字符串中注入任意字符串;也没有什么能阻止某人设置

$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++程序以在系统上运行任意代码。非常糟糕

即使您将查询字符串净化为一个有效的grep模式,如果有人以某种方式提供复杂的超长grep模式,仍然可能存在拒绝服务攻击。因此,限制长度也是一个好主意。
这不是C代码,它是C++。你可以用相应的Prtf或Poice调用替换CUT来生成C代码。其他的一切都可以用C语言完成。顺便说一句,你应该添加必要的include来完成这个示例。至于代码的作用,那么。。。代码所做的是1将环境变量$QUERY_STRING的内容附加到字符串t,2将第二个strcat的所有内容都附加到字符串,3执行以这种方式生成的命令行。问题:1如果$QUERY\u字符串的内容太大,以至于所有内容加起来都超过1023字节,则缓冲区溢出2$QUERY\u字符串可能包含可能会被删除的“邪恶”命令executed@IngoLeonhardt:由于查询字符串的内容未在命令中引用,即使是一点点空白也会成为问题。我不会把这个代码称为一个合适的C++——它比原始的效率低而且更难。另外,它仍然包含注入漏洞。@C.M.:关于该漏洞的观点,但我确实将其标记为注入漏洞。至于效率,这里不考虑这一点。你是说几根弦的构造吗?你是对的,我本可以使用std::stringstream,但我认为这会更简单。现在我改变了。我在这里抗议使用专有名词——因为新代码比旧代码更冗长,所以它会给人一种印象,即正确的C++代码比C语言更冗长。我也反对C++对i/o使用IOFFROW的概念——在C++代码中使用CSTDLIB/ETC没有什么错,事实上,在我的经验中,IOSWATIOLILB创建的问题比它解决的更多。@ C.M.:好,让旧代码做新代码所做的事情会使它变得更加冗长;但是,我不介意更多的冗长,如果它不是可怕的和多余的,如果它允许澄清。另外,旧代码已经在I/O中使用iostreams,这不是我添加的内容。我也不是特别喜欢iostreams。
#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
}
$ export QUERY_STRING=init
$ ./the_program
Content-type:text/html


Sun 3 Jun 2018 21:48:56
$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}'