如果有人能够完全解释我代码的作用,我会很高兴。我知道有一个缓冲区溢出和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;
}
答案 0 :(得分:1)
tl;dr: This is what your code does, as a shell script:
#!/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}'
Now for the longer answer.
First, let's make that thing into C++ rather than C (like your tag suggests you're asking about) with a bit of error handling, then talk about what's going on:
#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
}
So, we're creating a command-line here which we then execute using the system()
function. It's an invocation of a ps
command with some switches, followed by some text processing with grep
, head
and awk
- using the pipe mechanism to move the output of each command to the next. They key part is that we use the environment variable QUERY_STRING
to filter the ps
results, i.e. we list processes which match some phrase. If we compile this program, set the environment variable and run, this is what it looks like:
$ export QUERY_STRING=init
$ ./the_program
Content-type:text/html
Sun 3 Jun 2018 21:48:56
What this has given us is the start time of the first process whose command-line doesn't include the phrase "init". So now you can guess my system has been up since yesterday...
Finally, as a network guy, you probably realize the "Content-type" mumbo-jumbo and the double-newline is a MIME header, so this output is probably intended to be used as an HTTP response. Probably this is intended as some sort of CGI script.
The second vulnerability has to do with the system
command. We're injecting an arbitrary string into the string we're creating; and there's nothing preventing someone from setting
$export QUERY_STRING="dummy; rm -rf $HOME ; echo"
in which case you would run:
ps -eo lstart,cmd | grep dummy; rm -rf $HOME ; echo | grep -v init | head -n 1 | awk '{ print $1" "$3" "$2" "$5" "$4}'
and this would delete everything under the effective user's home directory. Or it could be any command, including compilation of a custom C/C++ program to run some arbitrary code on your system. Very bad.
答案 1 :(得分:0)
This just declares the variable status
int status;
This declared t, with the C-String "ps -eo lstart,cmd | grep ".
t
has a maximum of 1024 bytes in capacity (1023 for string + 1 byte for \0
)
char t[1024]="ps -eo lstart,cmd | grep ";
Print the string below
cout << "Content-type:text/html\r\n\r\n"<<endl;
get environment variable QUERY_STRING
char *value = getenv("QUERY_STRING");
concatenate the value above to t
. Here you may have the buffer overflow because you don't know the size of the string in value
and it may be longer than 1024 bytes
strcat(t,value);
Invoke the system()
function for another concatenation of the previous t
with all these grep, etc, etc commands... here you could have another buffer overflow, once t
may overflow its 1024 bytes here as well.
status = system(strcat(t," | grep -v grep | head -n 1 | awk '{ print $1\" \"$3\" \"$2\" \"$5\" \"$4}'"));