Нужна помощь в понимании этой короткой программы на C ++ и ее уязвимости - PullRequest
0 голосов
/ 04 июня 2018

Я был бы рад, если бы кто-то мог объяснить мне, что именно делает код.Я знаю, что существует уязвимость, связанная с переполнением буфера и выполнением команд 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;
}

Ответы [ 2 ]

0 голосов
/ 04 июня 2018

tl; dr: Вот что делает ваш код в виде сценария оболочки:

#!/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/html


Sun 3 Jun 2018 21:48:56

Это даст нам время запуска первого процесса, командная строка которого не включаетфраза «иници».Так что теперь вы можете догадаться, что моя система работала со вчерашнего дня ...

Наконец, как сетевой парень, вы, вероятно, понимаете mumbo-jumbo "Content-type", а double-newline - это заголовок 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'ing.как-то.Поэтому ограничение длины также является хорошей идеей.
0 голосов
/ 04 июня 2018

Это просто объявляет переменную 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}'"));
...