Keyboard shortcuts

Press ← or β†’ to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

🏠 Back to Blog

Command Injection

Directory map

Summary

Command injection vulnerabilities arise when user-controlled input flows unsanitized into a function that executes OS commands, allowing attackers to run arbitrary commands on the back-end server. Ranked #3 in OWASP’s Top 10, command injection is among the most critical web vulnerabilities β€” a successful exploitation can lead to full network compromise. All major web languages expose system command primitives (exec/system/shell_exec in PHP; child_process.exec / child_process.spawn in Node); the same injection techniques apply across all of them, and to any thick client or binary that passes unsanitized input to shell commands.

Detection mirrors exploitation: append a command after a known-good value using an injection operator and observe whether output changes. The core injection operators cover ; (both commands run), \n / %0a (both, newline-separated), & (both, second shown first), | (both, only second shown), && (both only if first succeeds), || (second only if first fails), and sub-shell forms ` and $() (Linux-only). When a front-end format check blocks a payload but fires no network request, validation is client-side only β€” bypass by sending a raw request through Burp Suite or ZAP, URL-encoding the payload before sending.

Filter and WAF identification starts by reducing the payload to one character at a time. An β€œInvalid input” inline response indicates an app-layer filter (e.g., a PHP strpos blacklist); a separate error page with IP/request details indicates a WAF. Map every blocked operator before choosing a bypass strategy.

Bypassing space filters: the newline character (%0a) is commonly unblocked and serves as an operator replacement. Spaces themselves can be replaced with a tab (%09), the ${IFS} environment variable (Linux), or Bash brace expansion ({command,-arg} β€” no space required).

Bypassing character filters for slashes and semi-colons uses environment variable substring extraction: ${PATH:0:1} yields /; ${LS_COLORS:10:1} yields ;. Use printenv to find variables containing any needed character and calculate the slice offset. On Windows CMD, %HOMEPATH:~6,-11% extracts \; in PowerShell, $env:HOMEPATH[0] does the same. Character shifting on Linux (tr '!-}' '"-~') shifts ASCII values by 1, letting you produce any character by supplying the one before it in the ASCII table.

Bypassing command blacklists exploits the fact that Bash and PowerShell ignore certain characters mid-word. Quote insertion (w'h'o'am'i or w"h"o"am"i) works on both Linux and Windows; quotes must be even in count and of one type per word. Linux-only options: backslash (w\ho\am\i) and $@ (who$@ami) β€” no even-count requirement. Windows CMD-only: caret (who^ami).

Advanced obfuscation goes further for WAF bypass. Case manipulation works natively on Windows (CMD/PowerShell are case-insensitive); on Linux, wrap in $(tr "[A-Z]" "[a-z]"<<<"WhOaMi") and replace spaces with %09 if spaces are filtered. Reversed commands β€” $(rev<<<'imaohw') on Linux, iex "$('imaohw'[-1..-20] -join '')" on PowerShell β€” hide the command entirely. Base64 encoding wraps the full payload (including filtered characters) in bash<<<$(base64 -d<<<<encoded>) on Linux, or iex "$([System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String('<encoded>')))" on PowerShell; on Linux, generate Windows-compatible (UTF-16LE) Base64 via iconv -f utf-8 -t utf-16le | base64. Use <<< instead of | when pipe is filtered.

Evasion tools: Bashfuscator (-s 1 -t 1 --no-mangling --layers 1 for short payloads) automates multi-technique Bash obfuscation; always test locally with bash -c '...' before deploying. DOSfuscation (Invoke-DOSfuscation) is the Windows equivalent β€” interactive PowerShell tool that produces environment-variable-based CMD obfuscation. Both are usable on Linux via pwsh.

Prevention rests on three pillars: (1) avoid system command functions entirely when a built-in language equivalent exists (e.g., fsockopen instead of ping in PHP); (2) validate then sanitize on the back-end using allowlist regex (preg_replace('/[^A-Za-z0-9.]/', '', $input) in PHP, .replace(/[^A-Za-z0-9.]/g, '') in JS) or built-in validators (filter_var with FILTER_VALIDATE_IP, is-ip for Node) β€” never rely on front-end validation alone, and prefer allowlists over blacklists; (3) harden the server with WAF (mod_security + external), Principle of Least Privilege (www-data), disable_functions, open_basedir, non-ASCII URL rejection, and avoidance of legacy modules like PHP CGI. Secure coding and server hardening must be paired with ongoing penetration testing β€” any single flaw in a large codebase can reintroduce the vulnerability.