HTTP Header Command Injection

HTTP header command injection is an OS command-injection variant in which an application reads a client-controlled HTTP request header — X-Forwarded-For, User-Agent, Client-IP, Referer, Accept-Language — and concatenates it, unsanitized, into a shell command (typically via PHP’s system(), exec(), shell_exec(), or backticks). The header value then breaks out of its intended argument position with shell metacharacters (;, &&, |, `, $()) and executes attacker-chosen commands with the web server’s privileges. It maps to CWE-77 (Improper Neutralization of Special Elements used in a Command).

Why headers are the payload carrier

Developers routinely treat request headers as metadata rather than user input, so header values bypass the validation applied to $_GET/$_POST parameters. The classic trigger is an application that needs the “real” client IP and reaches for X-Forwarded-For (which any client can set arbitrarily — see http) and then feeds that value to a network utility:

// firewall.php — the anti-pattern
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'];
system("sudo iptables -A INPUT -s $ip -j ACCEPT");

An attacker supplies:

X-Forwarded-For: 127.0.0.1 -j ACCEPT; sudo cat /root/root.txt ; echo

and the shell executes the injected commands between the ; separators. When the wrapped command runs under sudo (a common pattern for firewall/packet-filter management pages), the injection yields root directly.

Real-world instances

  • CVE-2016-10322 — Synology Photo Station before 6.3-2958: remote command execution via shell metacharacters in the X-Forwarded-For header passed to photo/login.php (CVSS 8.8).
  • CVE-2006-0957 — freeForum static code injection via X-Forwarded-For and Client-IP headers stored into an executable PHP data file.
  • Web shells — attackers hide command channels in User-Agent (system($_SERVER['HTTP_USER_AGENT'])) or Accept-Language, the latter evading access-log scrutiny because the header is rarely logged.
  • CTF/HTB pattern — a firewall.php-style page with sudo iptables access that concatenates X-Forwarded-For/Remote-Host into system(), exploited to read /root (HackTheBox Union).

Detection and exploitation notes

  • Headers don’t appear in most access logs, so header-channel injection and header-based web shells are quieter than parameter-based equivalents — test them on every input-reflecting endpoint.
  • Any header is fair game; prioritize X-Forwarded-For, Client-IP, User-Agent, Referer, Accept-Language, and custom X-* headers the application echoes or logs.
  • Confirm blind injection with out-of-band callbacks (DNS/HTTP to an interactsh-style listener) when command output isn’t reflected.
  • Remember the application may prepend/append fixed arguments — craft metacharacters that leave valid syntax on both sides (; cmd ; echo neutralizes a trailing suffix).

Defense

  • Never pass request data to a shell. Use language-native APIs (PHP’s Net_IPTables-style libraries, direct netlink/netfilter interfaces) instead of system().
  • If a subprocess is unavoidable, use escapeshellarg()/escapeshellcmd() and an allow-list (e.g., validate IPs with filter_var($ip, FILTER_VALIDATE_IP)).
  • Treat all headers as attacker-controlled; apply the same validation as body parameters.
  • Drop NOPASSWD sudo rules for the web-server user, and never let a web page invoke sudo iptables with request-derived arguments.

Sources

Related: http, sql-injection-attacks, burp-suite