Предотвращение атак с использованием командной строки - PullRequest
9 голосов
/ 05 сентября 2008

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

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

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

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

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

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

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

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

Ответы [ 7 ]

5 голосов
/ 05 сентября 2008

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

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

2 голосов
/ 08 сентября 2008

В C ++ в Windows , вы просто экранируете \ и «где необходимо, заключите аргумент в кавычки и 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;
    }
}

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

2 голосов
/ 05 сентября 2008

Когда вы Process.Start создаете новый процесс, укажите параметры в его аргументе Parameters вместо построения всей командной строки самостоятельно.

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

Завтра это проверю.

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

1 голос
/ 23 октября 2008

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

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

0 голосов
/ 05 сентября 2008

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

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

0 голосов
/ 05 сентября 2008

Ммм ...

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

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

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

0 голосов
/ 05 сентября 2008

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

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

...