unicornAll work
All theoryWeb security

Command injection

When input reaches a system shell — appending your own command for code execution.

In a nutshell Command injection is when a web app passes your input into a system shell command. Add your own command onto the end, and the server runs it — straight remote code execution, often as whatever user the web server runs as. Injection again, but the "language" you escape into is the operating system's shell.

The root cause

Some apps shell out to do a job — ping a host, convert an image — and build that command with your input glued in:

# the app runs:  ping -c 1 <your input>
# you enter:     8.8.8.8; whoami
# the shell runs TWO commands:
ping -c 1 8.8.8.8
whoami                # ← yours

The ; ends the intended command and starts yours. The shell runs both — it can't tell the app's command from your piece.

Analogy — dictating to an assistant. "Print this document — and email me the whole client list." A careless assistant does both, treating your add-on as part of the job. The shell is that assistant.

Shell metacharacters — the joints you exploit

Any of these, unfiltered, is an injection point:

Char Effect
; run the next command after this one
&& run the next only if this one succeeds
| pipe this command's output into the next
`cmd` / $(cmd) run a command, substitute its output
& run in the background

Finding it

Anywhere the app seems to run a system tool with your input, append a probe and watch:

; id            # does the output of id appear?
&& id
$(id)
; sleep 5       # does the response take 5s longer? (blind)

Why it's so dangerous — and where it leads

It's usually direct code execution, no clever chaining. Whatever the web server can do, you can now do — and it typically drops you as a low service account, which is exactly where privilege escalation begins:

command injection  →  low service shell (www-data)
              +    →  reverse shell for interactivity (see Reverse & bind shells)
              +    →  privilege escalation → root (see Linux privesc)
The fix Don't call the shell with user input at all — use the language's native library for the task (resolve DNS with a DNS library, not by running nslookup). If you must run a program, pass arguments as a separate list, never one concatenated string, so input can only be an argument, never a new command. Validate against an allow-list and run least-privileged. Same lesson: data stays data.
All theory