Skip to content

Commit 0ebb4d0

Browse files
Aegrahtradebot-elastic
authored andcommitted
[New Rule] Web Server Potential Command Injection Request (#5341)
* [New Rule] Web Server Potential Command Injection Request * Update variable names to use consistent casing * Add 'Domain: Network' tag to command injection rule * Update persistence_web_server_potential_command_injection.toml * adding missing tags * Update rules/cross-platform/persistence_web_server_potential_command_injection.toml Co-authored-by: shashank-elastic <[email protected]> * Update rules/cross-platform/persistence_web_server_potential_command_injection.toml Co-authored-by: shashank-elastic <[email protected]> --------- Co-authored-by: Terrance DeJesus <[email protected]> Co-authored-by: terrancedejesus <[email protected]> Co-authored-by: shashank-elastic <[email protected]> (cherry picked from commit 94ff4b0)
1 parent 8931283 commit 0ebb4d0

File tree

1 file changed

+196
-0
lines changed

1 file changed

+196
-0
lines changed
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
[metadata]
2+
creation_date = "2025/11/19"
3+
integration = ["nginx", "apache", "apache_tomcat", "iis", "network_traffic"]
4+
maturity = "production"
5+
updated_date = "2025/11/19"
6+
7+
[rule]
8+
author = ["Elastic"]
9+
description = """
10+
This rule detects potential command injection attempts via web server requests by identifying URLs that contain
11+
suspicious patterns commonly associated with command execution payloads. Attackers may exploit vulnerabilities in web
12+
applications to inject and execute arbitrary commands on the server, often using interpreters like Python, Perl, Ruby,
13+
PHP, or shell commands. By monitoring for these indicators in web traffic, security teams can identify and respond to
14+
potential threats early.
15+
"""
16+
from = "now-9m"
17+
interval = "10m"
18+
language = "esql"
19+
license = "Elastic License v2"
20+
name = "Web Server Potential Command Injection Request"
21+
risk_score = 21
22+
rule_id = "f3ac6734-7e52-4a0d-90b7-6847bf4308f2"
23+
severity = "low"
24+
tags = [
25+
"Domain: Web",
26+
"Domain: Network",
27+
"Use Case: Threat Detection",
28+
"Tactic: Reconnaissance",
29+
"Tactic: Persistence",
30+
"Tactic: Execution",
31+
"Tactic: Credential Access",
32+
"Tactic: Command and Control",
33+
"Data Source: Network Packet Capture",
34+
"Data Source: Nginx",
35+
"Data Source: Apache",
36+
"Data Source: Apache Tomcat",
37+
"Data Source: IIS",
38+
]
39+
timestamp_override = "event.ingested"
40+
type = "esql"
41+
query = '''
42+
from logs-network_traffic.http-*, logs-network_traffic.tls-*, logs-nginx.access-*, logs-apache.access-*, logs-apache_tomcat.access-*, logs-iis.access-*
43+
| where
44+
(url.original is not null or url.full is not null) and
45+
// Limit to 200 response code to reduce noise
46+
http.response.status_code == 200
47+
48+
| eval Esql.url_lower = case(url.original is not null, url.original, url.full)
49+
| eval Esql.url_lower = to_lower(Esql.url_lower)
50+
51+
| eval Esql.contains_interpreter = case(Esql.url_lower like "*python* -c*" or Esql.url_lower like "*perl* -e*" or Esql.url_lower like "*ruby* -e*" or Esql.url_lower like "*ruby* -rsocket*" or Esql.url_lower like "*lua* -e*" or Esql.url_lower like "*php* -r*" or Esql.url_lower like "*node* -e*", 1, 0)
52+
| eval Esql.contains_shell = case(Esql.url_lower like "*/bin/bash*" or Esql.url_lower like "*bash*-c*" or Esql.url_lower like "*/bin/sh*" or Esql.url_lower rlike "*sh.{1,2}-c*", 1, 0)
53+
| eval Esql.contains_nc = case(Esql.url_lower like "*netcat*" or Esql.url_lower like "*ncat*" or Esql.url_lower rlike """.*nc.{1,2}[0-9]{1,3}(\.[0-9]{1,3}){3}.{1,2}[0-9]{1,5}.*""" or Esql.url_lower like "*nc.openbsd*" or Esql.url_lower like "*nc.traditional*" or Esql.url_lower like "*socat*", 1, 0)
54+
| eval Esql.contains_devtcp = case(Esql.url_lower like "*/dev/tcp/*" or Esql.url_lower like "*/dev/udp/*", 1, 0)
55+
| eval Esql.contains_helpers = case((Esql.url_lower like "*/bin/*" or Esql.url_lower like "*/usr/bin/*") and (Esql.url_lower like "*mkfifo*" or Esql.url_lower like "*nohup*" or Esql.url_lower like "*setsid*" or Esql.url_lower like "*busybox*"), 1, 0)
56+
| eval Esql.contains_sus_cli = case(Esql.url_lower like "*import*pty*spawn*" or Esql.url_lower like "*import*subprocess*call*" or Esql.url_lower like "*tcpsocket.new*" or Esql.url_lower like "*tcpsocket.open*" or Esql.url_lower like "*io.popen*" or Esql.url_lower like "*os.execute*" or Esql.url_lower like "*fsockopen*", 1, 0)
57+
| eval Esql.contains_privileges = case(Esql.url_lower like "*chmod*+x", 1, 0)
58+
| eval Esql.contains_downloader = case(Esql.url_lower like "*curl *" or Esql.url_lower like "*wget *" , 1, 0)
59+
| eval Esql.contains_file_read_keywords = case(Esql.url_lower like "*/etc/shadow*" or Esql.url_lower like "*/etc/passwd*" or Esql.url_lower like "*/root/.ssh/*" or Esql.url_lower like "*/home/*/.ssh/*" or Esql.url_lower like "*~/.ssh/*" or Esql.url_lower like "*/proc/self/environ*", 1, 0)
60+
| eval Esql.contains_base64_cmd = case(Esql.url_lower like "*base64*-d*" or Esql.url_lower like "*echo*|*base64*", 1, 0)
61+
| eval Esql.contains_suspicious_path = case(Esql.url_lower like "*/tmp/*" or Esql.url_lower like "*/var/tmp/*" or Esql.url_lower like "*/dev/shm/*" or Esql.url_lower like "*/root/*" or Esql.url_lower like "*/home/*/*" or Esql.url_lower like "*/var/www/*" or Esql.url_lower like "*/etc/cron.*/*", 1, 0)
62+
63+
| eval Esql.any_payload_keyword = case(
64+
Esql.contains_interpreter == 1 or Esql.contains_shell == 1 or Esql.contains_nc == 1 or Esql.contains_devtcp == 1 or
65+
Esql.contains_helpers == 1 or Esql.contains_sus_cli == 1 or Esql.contains_privileges == 1 or Esql.contains_downloader == 1 or
66+
Esql.contains_file_read_keywords == 1 or Esql.contains_base64_cmd == 1 or Esql.contains_suspicious_path == 1, 1, 0)
67+
68+
| keep
69+
@timestamp,
70+
Esql.url_lower,
71+
Esql.any_payload_keyword,
72+
Esql.contains_interpreter,
73+
Esql.contains_shell,
74+
Esql.contains_nc,
75+
Esql.contains_devtcp,
76+
Esql.contains_helpers,
77+
Esql.contains_sus_cli,
78+
Esql.contains_privileges,
79+
Esql.contains_downloader,
80+
Esql.contains_file_read_keywords,
81+
Esql.contains_base64_cmd,
82+
Esql.contains_suspicious_path,
83+
source.ip,
84+
destination.ip,
85+
agent.id,
86+
http.request.method,
87+
http.response.status_code,
88+
user_agent.original,
89+
host.name,
90+
event.dataset
91+
92+
| stats
93+
Esql.event_count = count(),
94+
Esql.url_path_count_distinct = count_distinct(Esql.url_lower),
95+
96+
// General fields
97+
98+
Esql.host_name_values = values(host.name),
99+
Esql.agent_id_values = values(agent.id),
100+
Esql.url_path_values = values(Esql.url_lower),
101+
Esql.http.response.status_code_values = values(http.response.status_code),
102+
Esql.user_agent_original_values = values(user_agent.original),
103+
Esql.event_dataset_values = values(event.dataset),
104+
105+
// Rule Specific fields
106+
Esql.any_payload_keyword_max = max(Esql.any_payload_keyword),
107+
Esql.contains_interpreter_values = values(Esql.contains_interpreter),
108+
Esql.contains_shell_values = values(Esql.contains_shell),
109+
Esql.contains_nc_values = values(Esql.contains_nc),
110+
Esql.contains_devtcp_values = values(Esql.contains_devtcp),
111+
Esql.contains_helpers_values = values(Esql.contains_helpers),
112+
Esql.contains_sus_cli_values = values(Esql.contains_sus_cli),
113+
Esql.contains_privileges_values = values(Esql.contains_privileges),
114+
Esql.contains_downloader_values = values(Esql.contains_downloader),
115+
Esql.contains_file_read_keywords_values = values(Esql.contains_file_read_keywords),
116+
Esql.contains_base64_cmd_values = values(Esql.contains_base64_cmd),
117+
Esql.contains_suspicious_path_values = values(Esql.contains_suspicious_path)
118+
119+
by source.ip, agent.id
120+
121+
| where
122+
// Filter for potential command injection attempts with low event counts to reduce false positives
123+
Esql.any_payload_keyword_max == 1 and Esql.event_count < 5
124+
'''
125+
126+
[[rule.threat]]
127+
framework = "MITRE ATT&CK"
128+
129+
[[rule.threat.technique]]
130+
id = "T1505"
131+
name = "Server Software Component"
132+
reference = "https://attack.mitre.org/techniques/T1505/"
133+
134+
[[rule.threat.technique.subtechnique]]
135+
id = "T1505.003"
136+
name = "Web Shell"
137+
reference = "https://attack.mitre.org/techniques/T1505/003/"
138+
139+
[rule.threat.tactic]
140+
id = "TA0003"
141+
name = "Persistence"
142+
reference = "https://attack.mitre.org/tactics/TA0003/"
143+
144+
[[rule.threat]]
145+
framework = "MITRE ATT&CK"
146+
147+
[[rule.threat.technique]]
148+
id = "T1059"
149+
name = "Command and Scripting Interpreter"
150+
reference = "https://attack.mitre.org/techniques/T1059/"
151+
152+
[[rule.threat.technique.subtechnique]]
153+
id = "T1059.004"
154+
name = "Unix Shell"
155+
reference = "https://attack.mitre.org/techniques/T1059/004/"
156+
157+
[rule.threat.tactic]
158+
id = "TA0002"
159+
name = "Execution"
160+
reference = "https://attack.mitre.org/tactics/TA0002/"
161+
162+
[[rule.threat]]
163+
framework = "MITRE ATT&CK"
164+
165+
[[rule.threat.technique]]
166+
id = "T1071"
167+
name = "Application Layer Protocol"
168+
reference = "https://attack.mitre.org/techniques/T1071/"
169+
170+
[rule.threat.tactic]
171+
id = "TA0011"
172+
name = "Command and Control"
173+
reference = "https://attack.mitre.org/tactics/TA0011/"
174+
175+
[[rule.threat]]
176+
framework = "MITRE ATT&CK"
177+
178+
[[rule.threat.technique]]
179+
id = "T1595"
180+
name = "Active Scanning"
181+
reference = "https://attack.mitre.org/techniques/T1595/"
182+
183+
[[rule.threat.technique.subtechnique]]
184+
id = "T1595.002"
185+
name = "Vulnerability Scanning"
186+
reference = "https://attack.mitre.org/techniques/T1595/002/"
187+
188+
[[rule.threat.technique.subtechnique]]
189+
id = "T1595.003"
190+
name = "Wordlist Scanning"
191+
reference = "https://attack.mitre.org/techniques/T1595/003/"
192+
193+
[rule.threat.tactic]
194+
id = "TA0043"
195+
name = "Reconnaissance"
196+
reference = "https://attack.mitre.org/tactics/TA0043/"

0 commit comments

Comments
 (0)