Предотвращение атак с использованием командной строки

StackOverflow https://stackoverflow.com/questions/44799

Вопрос

В настоящее время мы создаем приложение, которое выполняет ряд внешних инструментов.Нам часто приходится передавать этим инструментам информацию, введенную пользователями в нашу систему.

Очевидно, что это большой кошмар безопасности, который ждет своего часа.

К сожалению, мы еще не нашли в .NET Framework классов, которые выполняли бы программы командной строки, обеспечивая при этом такую ​​же защиту от атак путем внедрения, как объекты IDbCommand для баз данных.

Прямо сейчас мы используем очень примитивную замену строк, которую, как я подозреваю, недостаточно:

protected virtual string Escape(string value)
{
      return value
        .Replace(@"\", @"\\")
        .Replace(@"$", @"\$")
        .Replace(@"""", @"\""")
        .Replace("`", "'")
      ;
}

Что вы, ребята, делаете, чтобы предотвратить атаки с использованием командной строки?Мы планируем реализовать очень строгое регулярное выражение, пропускающее только очень небольшое подмножество символов, но мне было интересно, есть ли лучший способ.

Некоторые уточнения:

  • Некоторые из этих инструментов не имеют API, для которых мы могли бы программировать.Если бы они это сделали, у нас не было бы этой проблемы.
  • Пользователи не выбирают инструменты для выполнения, они вводят метаданные, которые используют выбранные нами инструменты (например, внедряя метаданные, такие как уведомления об авторских правах, в целевые файлы).
Это было полезно?

Решение

Вы выполняете программы напрямую или через оболочку?Если вы всегда запускаете внешнюю программу, указывая полный путь к исполняемому файлу и исключая оболочку из уравнения, то вы на самом деле не подвержены каким-либо видам внедрения из командной строки.

РЕДАКТИРОВАТЬ:Доктор Флойд, оболочка отвечает за оценку таких вещей, как обратный апостроф.Нет оболочки, нет оценки оболочки.Очевидно, вы все равно должны знать о любых потенциальных ошибках безопасности в программах, которые вы вызываете, но я не думаю, что этот вопрос об этом.

Другие советы

Когда ты Процесс.Старт новый процесс, укажите параметры в его аргументе «Параметры» вместо того, чтобы создавать всю командную строку самостоятельно.

У меня нет времени на надлежащий тест, но я думаю, что это должно помочь защитить его на каком-то уровне.

Завтра проверим это.

РЕДАКТИРОВАТЬ: Ах, кто-то снова меня опередил.Но вот еще один момент:Попробуйте использовать Console.InputStream (не помню точное имя) для предоставления данных вместо передачи параметров, это возможное решение?например, исправить команду, чтобы она считывала данные с устройства CON, а затем вместо этого передавала данные через входной поток.

В С++ на Окна, вы просто экранируете \ и " там, где это необходимо, заключаете аргумент в кавычки и выполняете его ShellExecute.Тогда все, что находится внутри кавычек, следует рассматривать как текст.

Это должно иллюстрировать:


#include <iostream>
#include <string>
#include <windows.h>
#include <cstdlib>
using namespace std;

// Escape and quote string for use as Windows command line argument
string qEscape(const string& s) {
    string result("\"");
    for (string::const_iterator i = s.begin(); i != s.end(); ++i) {
        const char c = *i;
        const string::const_iterator next = i + 1;
        if (c == '"' || (c == '\\' && (next == s.end() || *next == '"'))) {
            result += '\\';
        }
        result += c;
    }
    result += '"';
    return result;
}

int main() {
    // Argument value to pass: c:\program files\test\test.exe
    const string safe_program = qEscape("c:\\program files\\test\\test.exe");
    cout << safe_program << " ";

    // Argument value to pass: You're the "best" around.
    const string safe_arg0 = qEscape("You're the \"best\" around.");

    // Argument value to pass: "Nothing's" gonna ever keep you down.
    const string safe_arg1 = qEscape("\"Nothing's\" gonna ever keep you down.");

    const string safe_args = safe_arg0 + " " + safe_arg1;
    cout << safe_args << "\n\n";

    // c:\program files\test\  to pass.
    const string bs_at_end_example = qEscape("c:\\program files\\test\\");
    cout << bs_at_end_example << "\n\n";

    const int result = reinterpret_cast<int>(ShellExecute(NULL, "open", safe_program.c_str(), safe_args.c_str(), NULL, SW_SHOWNORMAL));
    if (result < 33) {
        cout << "ShellExecute failed with Error code " << result << "\n";
        return EXIT_FAILURE;
    }
}

Но любой метод, который вы используете, вам следует тщательно протестировать, чтобы убедиться, что он действительно предотвращает инъекции.

Не используйте черный список для предотвращения инъекций.Если есть н способы внедрения кода, вы придумаете н - м где м > 0.

Используйте белый список допустимых параметров (или шаблонов).По своей природе это гораздо более ограничительно, но такова природа безопасности.

Что ж, если вы можете вызывать инструменты программно, без командной строки, это, вероятно, будет вашим лучшим вариантом.В противном случае вы потенциально можете запустить инструмент командной строки через пользователя, у которого нет абсолютно никакого доступа для каких-либо действий (за исключением, возможно, одного каталога, которому он не может причинить никакого вреда)...хотя это может привести к поломке инструмента, в зависимости от того, что он делает.

Просто заметьте: мне никогда не приходилось сталкиваться с этой проблемой, потому что мне никогда не приходилось вызывать инструмент командной строки из внешнего приложения, где инструмент требует ввода данных от пользователя.

Хм...

Похоже, у вас есть список допустимых команд, которые пользователи могут выполнять.Но вы не хотите, чтобы они казнили их всех.

Вы можете попытаться использовать реальную командную строку и убедиться, что файл существует хотя бы в «безопасном» месте.

Вы также можете решить проблему, увеличив количество интерфейсов, предоставив раскрывающийся список команд и параметров, которые они могли бы использовать.С вашей стороны это требует больше работы, но в конечном итоге это помогает пользователям.

Вы выполняете программы напрямую или через оболочку?Если вы всегда запускаете внешнюю программу, указывая полный путь к исполняемому файлу и исключая оболочку из уравнения, то вы на самом деле не подвержены каким-либо видам внедрения из командной строки.

@Курт Хагенлохер Обратный кавычек может вас убить.Если система Windows настроена «неправильно» или система unix позволяет это, то каталог &bt;del *&bt;сначала выполнит команду del *, а затем будет использовать вывод вместо del *, что в данном случае не имеет значения, поскольку нечего направлять (или ls)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top