Skip to main content

Befehlsinjection: So funktioniert sie, welche Risiken sie birgt und wie Sie sie verhindern

Artikel von

25. November 2020

0 Min. Lesezeit

Bei Befehlsinjection-Angriffen – auch als Betriebssystem-Befehlsinjection bezeichnet – wird eine Programmierlücke ausgenutzt, um Systembefehle ohne ausreichende Eingabevalidierung, Escaping oder Bereinigung auszuführen. Dadurch können Angreifer beliebige Befehle ausführen.

Welche Risiken bergen Befehlsinjections?

Je nach Einrichtung der Anwendung und Konfiguration des Prozesses, der sie ausführt, kann eine Befehlsinjection-Schwachstelle zu einer Rechteausweitung des Prozesses führen oder eine Remote-Reverse-Shell starten, über die eine böswillige Partei uneingeschränkt interagieren kann.

Wie funktionieren Befehlsinjection-Angriffe?

Um Programmierfehler im Zusammenhang mit Betriebssystem-Befehlsinjection-Angriffen zu verstehen, sehen wir uns verschiedene Befehlsinjection-Schwachstellen an, die in Node.js-basierten Anwendungen entdeckt wurden.

systeminformation ist eine Bibliothek für Betriebssysteminformationen, die wöchentlich mehr als 500.000 Downloads verzeichnet, regelmäßig gewartet wird (Commits) und von einer Community unterstützt wird. Das sehen wir auf der Seite zum Abhängigkeitszustand von Snyk Advisor:

npm-Seite des Pakets systeminformation mit einem Gesundheitswert von 75/100, dem wöchentlichen Downloadtrend und einem Diagramm zur Häufigkeit von Wartungs-Commits

Allerdings sind alle Versionen von system information vor Version 4.27.11 anfällig für Betriebssystem-Befehlsinjection, da die Bibliothek mehrere anfällige Methoden bereitstellt.

Sehen wir uns den Code der anfälligen Funktion inetChecksite() an. Erkennen Sie die Sicherheitslücke in diesem Code, die ein Beispiel für Befehlsinjection zeigt?

      let urlSanitized = util.sanitizeShellString(url).toLowerCase();
      if (urlSanitized) {
        let t = Date.now();
        if (_linux || _freebsd || _openbsd || _netbsd || _darwin || _sunos) {
          let args = ' -I --connect-timeout 5 -m 5 ' + urlSanitized + ' 2>/dev/null | head -n 1 | cut -d " " -f2';
          let cmd = 'curl';
          exec(cmd + args, function (error, stdout) {
          …

Aus diesem Codeausschnitt lassen sich mehrere Schlüsse ziehen:

  • Ein url-Parameter wird bereinigt. Vielleicht kann ich die Bereinigungsfunktionen mit etwas umgehen, das der Autor nicht bedacht hat?

  • Es wird eine unsichere API zum Starten von Betriebssystemprozessen verwendet: exec() fügt Befehle und ihre Argumente zu einem einzigen Shell-Befehl zusammen, der dann ausgeführt wird. Deshalb musste der Autor auch eine eigene Bereinigung von Befehlszeilenargumenten implementieren.

Die Variable urlSanitized wird mit den an die CLI übergebenen Argumenten verkettet.

Genau darin liegt die Sicherheitslücke: Die Variable urlSanitized wird verkettet. Der mit der Variable cmd referenzierte Befehl ist das Netzwerkprogramm curl. Was wäre, wenn wir curl einfach ein Befehlsargument als URL übergeben könnten?

Ein Befehlsinjection-Angriff lässt sich mit dem folgenden Proof of Concept versuchen. Dabei wird die URL an die anfällige Funktion übergeben, wie im ersten Argument der Funktion inetChecksite() zu sehen ist. Das folgende Beispiel zeigt eine Befehlsinjection:

 const si = require('systeminformation');
si.inetChecksite("https://snyk.io; touch /tmp/abc", (result) => console.log(result));

Das funktioniert hier allerdings nicht, weil dieses npm-Paket gefährliche Benutzereingaben wie das Semikolon (;) bereinigt.

Befehlszeilenargumente benötigen jedoch meist keine Sonderzeichen. Wir könnten eine URL als Benutzereingabe übergeben, etwa https://snyk.io -o hihi. Sie enthält ein Leerzeichen und verkettet das Positionsargument -o von curl, das das Ergebnis der Website in einer von uns kontrollierten Datei speichert.

Hier ist ein weiteres Beispiel für Befehlsinjection, das zeigt, wie ein solcher Angriff ablaufen kann und mit einer anfälligen Version von systeminformation@4.27.10 tatsächlich funktioniert:

const si = require('systeminformation');
si.inetChecksite("https://snyk.io -o hihi", (result) => console.log(result));

Dieser Commit hat die Bereinigung verbessert, um solche Befehlsinjection-Schwachstellen weiter einzudämmen:

Nebeneinander dargestellter Code-Diff in lib/internet.js mit erweiterter URL-Bereinigung durch zusätzliche Zeichenersetzungen.

Spickzettel zu Befehlsinjection

Aus weiteren Beispielen für Befehlsinjection können wir viel lernen. Darin haben wir Sicherheitslücken in Open-Source-Paketen und die jeweiligen Gegenmaßnahmen identifiziert, etwa bei den Schwachstellen hier und hier.

Mit den folgenden Maßnahmen können Sie Befehlsinjection-Angriffe verhindern:

  1. Übergeben Sie keine Benutzereingaben an Befehle, die Ihre Anwendung ausführt.

  2. Verwenden Sie zum Ausführen von Befehlen ausschließlich sichere APIs wie execFile(). Anders als andere APIs erwartet sie den Befehl als ersten Parameter und ein Array mit Befehlszeilenargumenten als zweiten Funktionsparameter. So wird sichergestellt, dass der Befehl selbst ein gültiges Programm sein muss und nicht aus gefährlichen Eingaben besteht.

  3. Achten Sie bei der Verwendung von execFile() darauf, dass der Benutzer den Programmnamen nicht kontrollieren kann. Stellen Sie außerdem sicher, dass Sie Benutzereingaben den Befehlsargumenten zuordnen, statt sie unverändert an die Programmausführung weiterzugeben.

  4. Prüfen Sie vorsichtshalber auch, ob Benutzereingaben dem erwarteten Format entsprechen. Erwartet ein Funktionsparameter beispielsweise eine URL, sollten Sie validieren, ob die Eingabe eine gültige URL ist. So hätte sich die oben erwähnte Befehlsinjection-Schwachstelle im npm-Paket systeminformation verhindern lassen.

Befehlsinjection-Angriffe in den OWASP Top 10

Um zu zeigen, wie verbreitet Betriebssystem-Befehlsinjection-Angriffe sind, habe ich alle öffentlich bekannten Sicherheitslücken aufgerufen, die das Snyk Security Team für Oktober 2020 veröffentlicht hat, und sie nach dem JavaScript-Ökosystem auf npm gefiltert. Wie Sie sehen, wurden allein in der letzten Oktoberwoche zahlreiche Sicherheitslücken durch Command injection in npm-Paketen entdeckt.

Snyk Vulnerability DB-Seite mit Schwachstellensuche, Paketfiltern und einer Liste von npm-Schwachstellen mit Schweregrad und Veröffentlichungsdatum.

Zusammenfassend lässt sich sagen: Befehlsinjection-Schwachstellen sind häufiger, als Sie vielleicht denken. Kein Wunder also, dass Injection-Angriffe einen berüchtigten Platz in den OWASP Top 10 der Web-Sicherheitsrisiken haben – sie sind weit verbreitet und treten in vielen Formen auf, etwa als SQL-Injection-Angriffe. Ich empfehle Ihnen dringend, Ihre Git-Repositories mit Snyk zu verbinden, um sie auf Befehlsinjection-Schwachstellen zu testen und diese zu beheben. Vielleicht findet Snyk auch noch weitere. Snyk ist kostenlos und Ihre Projekte sind im Handumdrehen überwacht!

Starten Sie mit Capture the Flag

Erfahren Sie in unserem virtuellen On-Demand-Workshop für Einsteiger, wie Sie Capture-the-Flag-Herausforderungen lösen.

Weiterlesen

Blog

Frontier-Modelle fanden die Schwachstellen. Nur der Angreifer fand die Angriffsketten.

Die statische Analyse fand die Schwachstellen, doch erst Live-Angriffstests bewiesen, wie sie sich zu Angriffen verketten lassen. Ein Vergleich von Evo COS, Claude Security und Claude Code Security.

feature insights context
Blog

Autonome Angriffe sind bereits Realität. Die Verteidigung muss Schritt halten.

Autonome Angreifer verkürzen das Zeitfenster für die Verteidigung. Erfahren Sie, wie kontinuierliches Erkennen, Beheben, Validieren und Verhindern Sicherheitsteams helfen kann, Schritt zu halten.

Blog

Warum KI-Coding-Agenten immer wieder fehlerhafte Zugriffskontrollen schreiben

KI-Coding-Agenten können Autorisierungslogik erzeugen, die kompiliert und die Prüfung besteht, dabei aber die Daten eines Mandanten für einen anderen offenlegt. Erfahren Sie, warum fehlerhafte Zugriffskontrollen schwer zu erkennen sind und wie Sie sie verhindern.