Aufruf von Prozessen mit sichtbaren sensiblen Informationen

Beschreibung

Aufruf von Prozessen mit sichtbaren sensiblen Informationen ist eine Schwachstelle, die auftritt, wenn ein Prozess mit sensiblen Daten aufgerufen wird, die über Befehlszeilenargumente, Umgebungsvariablen oder andere Mechanismen übergeben werden, die von anderen Prozessen auf dem Betriebssystem beobachtet werden können. Auf den meisten Betriebssystemen kann jeder Benutzer die Befehlszeilenargumente und manchmal Umgebungsvariablen von Prozessen anderer Benutzer über Dienstprogramme wie ps, top, /proc-Dateisystem oder Task-Manager einsehen. Wenn sensible Informationen wie Passwörter, API-Schlüssel, kryptografische Geheimnisse oder persönliche Daten über diese sichtbaren Kanäle übergeben werden, werden sie für lokale Angreifer zugänglich und können in Shell-Verläufen, Prozess-Abrechnungsdatensätzen oder Systemüberwachungstools protokolliert werden.

Risiko

Das Übergeben sensibler Informationen über sichtbare Prozessattribute erzeugt erhebliche Sicherheitsrisiken in Mehrbenutzern- und Shared-Hosting-Umgebungen. Lokale Benutzer können Anmeldedaten extrahieren, indem sie einfach Prozesslisten überwachen, was unbefugten Zugriff auf Datenbanken, APIs und andere geschützte Ressourcen ermöglicht. Shell-Verlaufsdateien können Befehle mit Passwörtern unbegrenzt aufbewahren und schaffen dauerhafte Offenlegung, selbst nachdem der unmittelbare Prozess beendet ist. Systemüberwachungs- und Logging-Tools erfassen oft Befehlszeilenargumente und speichern potenziell Anmeldedaten in Logdateien, die für Administratoren zugänglich sind oder über Log-Aggregationsdienste durchsickern. Container-Orchestrierungssysteme und Cloud-Plattformen können diese Argumente über ihre Verwaltungsschnittstellen offenlegen. Das Risiko wird in Entwicklungs- und Debugging-Szenarien verstärkt, wo Entwickler routinemäßig Anmeldedaten auf Befehlszeilen übergeben können, ohne die Offenlegung zu berücksichtigen.

Lösung

Übergeben Sie niemals sensible Informationen über Befehlszeilenargumente oder Umgebungsvariablen, die für andere Prozesse sichtbar sein können. Lesen Sie stattdessen Anmeldedaten aus Konfigurationsdateien mit eingeschränkten Berechtigungen (Modus 600), verwenden Sie Credential-Management-Systeme wie HashiCorp Vault oder AWS Secrets Manager, oder akzeptieren Sie Eingaben über Standardeingabe (stdin). Für Umgebungsvariablen verwenden Sie Mechanismen, die die Variablensichtbarkeit schützen, oder übergeben Sie Referenzen auf Geheimnisse statt der Geheimnisse selbst. Implementieren Sie Wrapper-Skripte, die Anmeldedaten aus sicheren Quellen lesen und sie nur in die private Umgebung des Kindprozesses exportieren. Löschen Sie Befehlszeilenargumente nach dem Parsen, wenn die Programmiersprache dies erlaubt. Deaktivieren Sie den Shell-Verlauf für Sitzungen, die sensible Befehle verarbeiten, und konfigurieren Sie die Prozessabrechnung, um sensible Argumente auszuschließen oder zu maskieren. Überprüfen Sie alle Prozessaufrufe im Code auf Anmeldedaten-Offenlegung.

Häufige Auswirkungen

AuswirkungDetails
VertraulichkeitBereich: Vertraulichkeit

Sensible Informationen wie Passwörter, API-Schlüssel und kryptografische Geheimnisse werden für andere Benutzer auf dem System lesbar. Diese Offenlegung ermöglicht unbefugten Zugriff auf geschützte Ressourcen und kann zu weiterer Systemkompromittierung führen.

Beispielcode

Anfälliger Code (Python)

Der folgende Code demonstriert das Übergeben sensibler Informationen über sichtbare Kanäle:

import subprocess
import os

class VulnerableProcessInvoker:
    """Beispiele für anfällige Prozessaufrufmuster"""

    def connect_database_vulnerable(self, password):
        # Anfällig: Passwort sichtbar in Prozessliste via 'ps aux'
        # Jeder kann ausführen: ps aux | grep mysql
        cmd = f"mysql -u admin -p{password} -h localhost mydb"
        subprocess.run(cmd, shell=True)

    def backup_with_credentials(self, aws_secret):
        # Anfällig: AWS-Anmeldedaten sichtbar in Prozessargumenten
        cmd = [
            "aws", "s3", "sync",
            "--access-key-id", "AKIAIOSFODNN7EXAMPLE",
            "--secret-access-key", aws_secret,
            "/data/", "s3://mybucket/"
        ]
        subprocess.run(cmd)

    def curl_with_auth(self, api_key):
        # Anfällig: API-Schlüssel in Befehlszeile
        subprocess.run([
            "curl", "-H", f"Authorization: Bearer {api_key}",
            "https://api.example.com/data"
        ])

    def run_with_env_visible(self, secret):
        # Anfällig: Umgebungsvariable kann sichtbar sein
        # /proc/<pid>/environ auf Linux
        env = os.environ.copy()
        env['SECRET_KEY'] = secret
        env['DATABASE_PASSWORD'] = secret

        subprocess.run(["./process_data.sh"], env=env)

    def pgp_decrypt_vulnerable(self, passphrase):
        # Anfällig: PGP-Passphrase auf Befehlszeile
        # Sichtbar für alle Benutzer, gespeichert im Shell-Verlauf
        cmd = f"gpg --passphrase {passphrase} --decrypt secret.gpg"
        subprocess.run(cmd, shell=True)

Alle Beispiele legen sensible Anmeldedaten über Befehlszeilenargumente offen, die via ps aux oder /proc/<pid>/cmdline sichtbar sind.

Korrigierter Code (Python)

import subprocess
import os
import tempfile
import stat

class SecureProcessInvoker:
    """Sichere Muster für Prozessaufrufe mit Anmeldedaten"""

    def connect_database_secure(self, password):
        # Korrigiert: MySQL-Optionsdatei mit eingeschränkten Berechtigungen verwenden
        with tempfile.NamedTemporaryFile(mode='w', suffix='.cnf', delete=False) as f:
            f.write(f"[client]\npassword={password}\n")
            options_file = f.name

        # Restriktive Berechtigungen setzen (nur Eigentümer lesen)
        os.chmod(options_file, stat.S_IRUSR)

        try:
            # Passwort nicht sichtbar in Prozessliste
            cmd = ["mysql", f"--defaults-extra-file={options_file}",
                   "-u", "admin", "-h", "localhost", "mydb"]
            subprocess.run(cmd)
        finally:
            os.unlink(options_file)

    def backup_with_credentials_secure(self):
        # Korrigiert: AWS-Anmeldedatei oder IAM-Rolle verwenden
        # Anmeldedaten gespeichert in ~/.aws/credentials mit Modus 600
        # Oder Instance-Profil/IAM-Rolle verwenden (keine Anmeldedaten nötig)
        subprocess.run([
            "aws", "s3", "sync",
            "/data/", "s3://mybucket/"
        ])  # Verwendet Standard-Credential-Chain

    def curl_with_auth_secure(self, api_key):
        # Korrigiert: stdin oder Konfigurationsdatei für sensible Header verwenden
        # Option 1: Via stdin mit -K - übergeben
        config = f'header = "Authorization: Bearer {api_key}"'

        process = subprocess.Popen(
            ["curl", "-K", "-", "https://api.example.com/data"],
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE
        )
        stdout, _ = process.communicate(input=config.encode())
        return stdout

    def run_with_protected_env(self, secret):
        # Korrigiert: Secrets-Manager verwenden oder via Dateideskriptor übergeben
        # Pipe erstellen um Geheimnis an Kindprozess zu übergeben
        read_fd, write_fd = os.pipe()

        # Geheimnis in Pipe schreiben
        os.write(write_fd, secret.encode())
        os.close(write_fd)

        # Kind liest von Dateideskriptor
        env = os.environ.copy()
        env['SECRET_FD'] = str(read_fd)  # Nur die FD-Nummer, nicht das Geheimnis

        subprocess.run(["./process_data.sh"], env=env, pass_fds=(read_fd,))

    def pgp_decrypt_secure(self, passphrase):
        # Korrigiert: pinentry verwenden oder Passphrase via Dateideskriptor übergeben
        process = subprocess.Popen(
            ["gpg", "--passphrase-fd", "0", "--batch", "--decrypt", "secret.gpg"],
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE
        )
        stdout, stderr = process.communicate(input=passphrase.encode())
        return stdout

    def use_secrets_manager(self):
        """Best Practice: Secrets-Manager verwenden"""
        from secrets_manager import get_secret

        # Geheimnis wird intern abgerufen, nie auf Befehlszeile
        secret = get_secret("database/password")

        # Direkt an Datenbanktreiber übergeben, nicht via subprocess
        import mysql.connector
        conn = mysql.connector.connect(
            host="localhost",
            user="admin",
            password=secret,
            database="mydb"
        )
        return conn

Die Korrekturen verwenden Konfigurationsdateien mit restriktiven Berechtigungen, stdin für die Übergabe von Geheimnissen, Dateideskriptoren, Credential-Chains und Secrets-Manager anstelle sichtbarer Befehlszeilenargumente.


Ausgenutzt in der Praxis

Kubernetes Secrets in Umgebungsvariablen (Mehrere Cloud-Deployments, Fortlaufend)

Container-Orchestrierungsplattformen haben Anmeldedaten offengelegt, wenn Entwickler Geheimnisse als Umgebungsvariablen übergeben, die in Pod-Spezifikationen, Container-Inspektionsbefehlen und Überwachungssystemen sichtbar sind. Angreifer mit Cluster-Zugang können Geheimnisse durch Inspektion laufender Container enumerieren. Große Cloud-Anbieter haben mehrere Vorfälle dokumentiert und empfehlen jetzt die Verwendung von gemounteten Secrets-Volumes oder externen Secrets-Managern.

Jenkins Credential-Leakage in Build-Logs (Mehrere Organisationen, 2019)

Jenkins-Build-Systeme protokollierten häufig Befehlszeilenargumente mit Anmeldedaten, die an Build-Skripte übergeben wurden. Diese Logs waren oft für Entwickler zugänglich, die keinen Zugang zu Produktions-Anmeldedaten haben sollten, oder wurden über Log-Aggregationssysteme offengelegt. Dies führte dazu, dass Jenkins Credential-Maskierung implementierte und das Credentials-Plugin empfahl.

Docker Run Command Credential-Offenlegung (Mehrere Organisationen, Fortlaufend)

Docker-Befehle, die Anmeldedaten via -e PASSWORD=secret übergeben, legen diese Werte über docker inspect, Prozesslisten und Container-Logs offen. Sicherheitsforscher haben offengelegte Datenbankpasswörter, API-Schlüssel und Verschlüsselungsgeheimnisse in laufenden Containern auf kompromittierten Hosts gefunden. Die Docker-Dokumentation empfiehlt jetzt die Verwendung von Docker Secrets für sensible Daten.


Tools zum Testen/Ausnutzen

  • ps aux / top — Standard-Unix-Dienstprogramme zum Anzeigen von Prozess-Befehlszeilenargumenten aller laufenden Prozesse.

  • pspy — Tool zur Überwachung von Linux-Prozessen ohne Root-Berechtigungen, nützlich zum Erfassen von Anmeldedaten in Prozessargumenten.

  • Trivy — Container-Sicherheitsscanner, der Geheimnisse in Umgebungsvariablen und Container-Konfigurationen erkennt.


CVE-Beispiele

  • CVE-2021-32638 — Code-Analyse-Produkt legte Zugangs-Tokens über Befehlszeilenparameter und Umgebungsvariablen offen.

  • CVE-2005-1387 — Anwendung übergab Passwörter auf Befehlszeile, sichtbar via ps-Befehl.

  • CVE-2001-1565 — Benutzername und Passwort auf Befehlszeile sichtbar durch Prozesslisting.

  • CVE-1999-1270 — PGP-Passphrase als Befehlszeilenargument übergeben, anderen Benutzern offengelegt.

  • CVE-2004-1058 — Kernel-Race-Condition ermöglichte Zugriff auf Umgebungsvariablen während des Prozess-Spawnings.


Referenzen

  1. MITRE Corporation. "CWE-214: Invocation of Process Using Visible Sensitive Information." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/214.html

  2. Docker Documentation. "Manage Sensitive Data with Docker Secrets." https://docs.docker.com/engine/swarm/secrets/

  3. Kubernetes Documentation. "Secrets Security Properties." https://kubernetes.io/docs/concepts/configuration/secret/#security-properties

  4. OWASP Foundation. "Credential Management Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Credential_Management_Cheat_Sheet.html