Frage

Wir erstellen derzeit eine Anwendung, die eine Reihe externer Tools ausführt.Wir müssen häufig von Benutzern in unser System eingegebene Informationen an diese Tools weitergeben.

Offensichtlich ist dies ein großer Sicherheitsalbtraum, der darauf wartet, Wirklichkeit zu werden.

Leider haben wir im .NET Framework noch keine Klassen gefunden, die Befehlszeilenprogramme ausführen und gleichzeitig den gleichen Schutz vor Injektionsangriffen bieten wie die IDbCommand-Objekte für Datenbanken.

Im Moment verwenden wir eine sehr primitive String-Ersetzung, die meiner Meinung nach eher unzureichend ist:

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

Was tun Sie, um Befehlszeilen-Injection-Angriffe zu verhindern?Wir planen, einen regulären Ausdruck zu implementieren, der sehr streng ist und nur eine sehr kleine Teilmenge von Zeichen durchlässt, aber ich habe mich gefragt, ob es einen besseren Weg gibt.

Einige Klarstellungen:

  • Einige dieser Tools verfügen nicht über APIs, mit denen wir programmieren können.Wenn sie es täten, hätten wir dieses Problem nicht.
  • Die Benutzer wählen keine Tools zur Ausführung aus, sondern geben Metadaten ein, die die von uns ausgewählten Tools verwenden (z. B. indem sie Metadaten wie Urheberrechtshinweise in Zieldateien einfügen).
War es hilfreich?

Lösung

Führen Sie die Programme direkt aus oder gehen Sie über die Shell?Wenn Sie ein externes Programm immer starten, indem Sie den vollständigen Pfadnamen zur ausführbaren Datei angeben und die Shell außen vor lassen, sind Sie nicht wirklich anfällig für irgendeine Art von Befehlszeileninjektion.

BEARBEITEN:DrFloyd, die Shell ist für die Auswertung von Dingen wie dem Backtick verantwortlich.Keine Shell, keine Shell-Bewertung.Natürlich müssen Sie sich immer noch über mögliche Sicherheitsprobleme in den Programmen im Klaren sein, die Sie aufrufen – aber ich glaube nicht, dass es bei dieser Frage darum geht.

Andere Tipps

Wenn du Prozess.Start Geben Sie für einen neuen Prozess die Parameter in seinem Parameter-Argument an, anstatt die gesamte Befehlszeile selbst zu erstellen.

Ich habe keine Zeit für einen richtigen Test, aber ich denke, das sollte helfen, die Sache bis zu einem gewissen Grad abzusichern.

Werde das morgen testen.

BEARBEITEN: Ah, da ist mir schon wieder jemand zuvorgekommen.Aber hier ist noch ein weiterer Punkt:Versuchen Sie, Console.InputStream (ich kann mich nicht an den genauen Namen erinnern) zu verwenden, um Daten bereitzustellen, anstatt Parameter zu übergeben. Ist das eine mögliche Lösung?Korrigieren Sie beispielsweise den Befehl, sodass er vom CON-Gerät liest und Sie die Daten dann stattdessen über den Eingabestream bereitstellen.

In C++ auf Windows, entkommen Sie einfach \ und ", wo nötig, zitieren Sie das Argument und führen Sie ShellExecute aus.Dann sollte alles innerhalb der Anführungszeichen als Text behandelt werden.

Dies soll veranschaulichen:


#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;
    }
}

Aber Sie sollten jede Methode, die Sie verwenden, gründlich testen, um sicherzustellen, dass sie die Injektion wirklich verhindert.

Verwenden Sie keine schwarze Liste zur Verhinderung von Injektionen.Wenn es gibt N Möglichkeiten, Code einzuschleusen, werden Sie sich vorstellen n - m Wo m > 0.

Verwenden Sie eine Whitelist akzeptierter Parameter (oder Muster).Es ist von Natur aus viel restriktiver, aber das liegt in der Natur der Sicherheit.

Nun, wenn Sie die Tools programmgesteuert ohne die Befehlszeile aufrufen können, wäre das wahrscheinlich die beste Option.Andernfalls könnten Sie das Befehlszeilentool möglicherweise über einen Benutzer ausführen, der absolut keinen Zugriff auf irgendetwas hat (außer vielleicht auf ein einzelnes Verzeichnis, mit dem er keinen Schaden anrichten kann) ...Dies kann jedoch dazu führen, dass das Werkzeug kaputt geht, je nachdem, was das Werkzeug tut.

Bitte beachten Sie, dass ich noch nie mit diesem Problem konfrontiert war, da ich noch nie ein Befehlszeilentool von einer externen Anwendung aus aufrufen musste, bei der das Tool Eingaben vom Benutzer erfordert.

Hmmm...

Es hört sich so an, als hätten Sie eine Liste gültiger Befehle, die die Benutzer ausführen können.Aber Sie wollen nicht, dass sie sie alle hinrichten.

Sie könnten versuchen, über die tatsächliche Befehlszeile zu überprüfen, ob die Datei zumindest am „sicheren“ Speicherort vorhanden ist.

Sie könnten das Problem auch mit mehr Schnittstellen lösen und eine Dropdown-Liste mit Befehlen und Parametern bereitstellen, die sie verwenden könnten.Es ist zwar mehr Arbeit für Sie, aber letztendlich hilft es den Benutzern.

Führen Sie die Programme direkt aus oder gehen Sie über die Shell?Wenn Sie ein externes Programm immer starten, indem Sie den vollständigen Pfadnamen zur ausführbaren Datei angeben und die Shell außen vor lassen, sind Sie nicht wirklich anfällig für irgendeine Art von Befehlszeileninjektion.

@Curt Hagenlocher Der Backtick kann dich töten.Wenn das Windows-System „falsch“ eingerichtet ist oder das Unix-System dies zulässt, wird ein dir &bt;del *&bt;führt zuerst den Befehl del * aus und verwendet dann die Ausgabe anstelle von del *, was in diesem Fall keine Rolle spielt, da dir (oder ls) nichts enthält.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top