Я был бы рад, если бы кто-то мог объяснить мне, что именно делает код. Я знаю, что существует уязвимость, связанная с переполнением буфера и выполнением команд 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;
}
ТЛ; др: Вот что делает ваш код в виде сценария оболочки:
#!/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
команда с некоторыми переключателями с последующей обработкой текста с grep
, head
а также awk
— использование механизма конвейера для перемещения вывода каждой команды на следующую. Их ключевой частью является то, что мы используем переменную среды QUERY_STRING
фильтровать ps
результаты, т.е. мы перечисляем процессы, которые соответствуют какой-то фразе. Если мы скомпилируем эту программу, установим переменную окружения и запустим, это выглядит так:
$ export QUERY_STRING=init
$ ./the_program
Content-type:text/htmlSun 3 Jun 2018 21:48:56
Это дало нам время запуска первого процесса, командная строка которого не включает фразу «init». Так что теперь вы можете догадаться, что моя система работала со вчерашнего дня …
Наконец, как сетевой парень, вы, вероятно, понимаете «контент-тип» mumbo-jumbo, а double-newline — это заголовок MIME, так что этот вывод, вероятно, предназначен для использования в качестве ответа HTTP. Вероятно, это задумано как своего рода CGI-скрипт.
Вторая уязвимость связана с 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 ++ для запуска произвольного кода в вашей системе. Очень плохой.
Это просто объявляет переменную status
int status;
Это объявило t, с C-String «ps -eo lstart, cmd | grep».
t
имеет максимум 1024 байта в емкости (1023 для строки + 1 байт для \0
)
char t[1024]="ps -eo lstart,cmd | grep ";
Распечатать строку ниже
cout << "Content-type:text/html\r\n\r\n"<<endl;
получить переменную среды QUERY_STRING
char *value = getenv("QUERY_STRING");
объединить значение выше, чтобы t
, Здесь у вас может быть переполнение буфера, потому что вы не знаете размер строки в value
и это может быть больше, чем 1024 байта
strcat(t,value);
Вызвать system()
функция для другого объединения предыдущего t
со всеми этими командами grep, etc, etc … здесь может произойти переполнение буфера, один раз t
может также переполнить свои 1024 байта здесь.
status = system(strcat(t," | grep -v grep | head -n 1 | awk '{ print $1\" \"$3\" \"$2\" \"$5\" \"$4}'"));