Skip to content

Commit 01ea0a8

Browse files
authored
Merge branch 'main' into new-rule-docker-exec-host-ref-via-priv-container
2 parents 9e9df60 + e19ce18 commit 01ea0a8

File tree

33 files changed

+982
-168
lines changed

33 files changed

+982
-168
lines changed

rules/cross-platform/multiple_alerts_elastic_defend_netsecurity_by_host.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
creation_date = "2025/11/18"
33
integration = ["endpoint", "panw", "fortinet_fortigate", "suricata"]
44
maturity = "production"
5-
updated_date = "2025/11/18"
5+
updated_date = "2025/11/28"
66

77
[rule]
88
author = ["Elastic"]
@@ -65,6 +65,9 @@ FROM logs-* metadata _id
6565
Esql.destination_ip_values = VALUES(destination.ip)
6666
by Esql.source_ip
6767
| where Esql.event_module_distinct_count >= 2
68+
| eval concat_module_values = MV_CONCAT(Esql.event_module_values, ",")
69+
// Make sure an endpoint alert is present along one of the network ones
70+
| where concat_module_values like "*endpoint*"
6871
| keep Esql.alerts_count, Esql.source_ip, Esql.destination_ip_values, Esql.host_id_values, Esql.user_name_values, Esql.event_module_values, Esql.message_values, Esql.process_executable_values
6972
'''
7073
note = """## Triage and analysis

rules/cross-platform/persistence_web_server_potential_command_injection.toml

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
[metadata]
22
creation_date = "2025/11/19"
3-
integration = ["nginx", "apache", "apache_tomcat", "iis", "network_traffic"]
3+
integration = ["nginx", "apache", "apache_tomcat", "iis"]
44
maturity = "production"
5-
updated_date = "2025/11/24"
5+
updated_date = "2025/12/01"
66

77
[rule]
88
author = ["Elastic"]
@@ -54,14 +54,12 @@ rule_id = "f3ac6734-7e52-4a0d-90b7-6847bf4308f2"
5454
severity = "low"
5555
tags = [
5656
"Domain: Web",
57-
"Domain: Network",
5857
"Use Case: Threat Detection",
5958
"Tactic: Reconnaissance",
6059
"Tactic: Persistence",
6160
"Tactic: Execution",
6261
"Tactic: Credential Access",
6362
"Tactic: Command and Control",
64-
"Data Source: Network Packet Capture",
6563
"Data Source: Nginx",
6664
"Data Source: Apache",
6765
"Data Source: Apache Tomcat",
@@ -71,26 +69,24 @@ tags = [
7169
timestamp_override = "event.ingested"
7270
type = "esql"
7371
query = '''
74-
from logs-network_traffic.http-*, logs-network_traffic.tls-*, logs-nginx.access-*, logs-apache.access-*, logs-apache_tomcat.access-*, logs-iis.access-*
72+
from logs-nginx.access-*, logs-apache.access-*, logs-apache_tomcat.access-*, logs-iis.access-*
7573
| where
76-
(url.original is not null or url.full is not null) and
7774
// Limit to 200 response code to reduce noise
7875
http.response.status_code == 200
7976
80-
| eval Esql.url_lower = case(url.original is not null, url.original, url.full)
81-
| eval Esql.url_lower = to_lower(Esql.url_lower)
82-
83-
| 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)
84-
| 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)
85-
| 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)
86-
| eval Esql.contains_devtcp = case(Esql.url_lower like "*/dev/tcp/*" or Esql.url_lower like "*/dev/udp/*", 1, 0)
87-
| 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)
88-
| 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)
89-
| eval Esql.contains_privileges = case(Esql.url_lower like "*chmod*+x", 1, 0)
90-
| eval Esql.contains_downloader = case(Esql.url_lower like "*curl *" or Esql.url_lower like "*wget *" , 1, 0)
91-
| 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)
92-
| eval Esql.contains_base64_cmd = case(Esql.url_lower like "*base64*-d*" or Esql.url_lower like "*echo*|*base64*", 1, 0)
93-
| 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)
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)
9490
9591
| eval Esql.any_payload_keyword = case(
9692
Esql.contains_interpreter == 1 or Esql.contains_shell == 1 or Esql.contains_nc == 1 or Esql.contains_devtcp == 1 or
@@ -99,7 +95,7 @@ from logs-network_traffic.http-*, logs-network_traffic.tls-*, logs-nginx.access-
9995
10096
| keep
10197
@timestamp,
102-
Esql.url_lower,
98+
Esql.url_original_to_lower,
10399
Esql.any_payload_keyword,
104100
Esql.contains_interpreter,
105101
Esql.contains_shell,
@@ -123,13 +119,13 @@ from logs-network_traffic.http-*, logs-network_traffic.tls-*, logs-nginx.access-
123119
124120
| stats
125121
Esql.event_count = count(),
126-
Esql.url_path_count_distinct = count_distinct(Esql.url_lower),
122+
Esql.url_path_count_distinct = count_distinct(Esql.url_original_to_lower),
127123
128124
// General fields
129125
130126
Esql.host_name_values = values(host.name),
131127
Esql.agent_id_values = values(agent.id),
132-
Esql.url_path_values = values(Esql.url_lower),
128+
Esql.url_path_values = values(Esql.url_original_to_lower),
133129
Esql.http.response.status_code_values = values(http.response.status_code),
134130
Esql.user_agent_original_values = values(user_agent.original),
135131
Esql.event_dataset_values = values(event.dataset),

rules/cross-platform/reconnaissance_web_server_discovery_or_fuzzing_activity.toml

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
[metadata]
22
creation_date = "2025/11/19"
3-
integration = ["network_traffic", "nginx", "apache", "apache_tomcat", "iis"]
3+
integration = ["nginx", "apache", "apache_tomcat", "iis"]
44
maturity = "production"
5-
updated_date = "2025/11/24"
5+
updated_date = "2025/12/01"
66

77
[rule]
88
author = ["Elastic"]
@@ -52,10 +52,8 @@ rule_id = "8383a8d0-008b-47a5-94e5-496629dc3590"
5252
severity = "low"
5353
tags = [
5454
"Domain: Web",
55-
"Domain: Network",
5655
"Use Case: Threat Detection",
5756
"Tactic: Reconnaissance",
58-
"Data Source: Network Packet Capture",
5957
"Data Source: Nginx",
6058
"Data Source: Apache",
6159
"Data Source: Apache Tomcat",
@@ -65,14 +63,12 @@ tags = [
6563
timestamp_override = "event.ingested"
6664
type = "esql"
6765
query = '''
68-
from logs-network_traffic.http-*, logs-network_traffic.tls-*, logs-nginx.access-*, logs-apache.access-*, logs-apache_tomcat.access-*, logs-iis.access-*
66+
from logs-nginx.access-*, logs-apache.access-*, logs-apache_tomcat.access-*, logs-iis.access-*
6967
| where
70-
(url.original is not null or url.full is not null) and
7168
http.request.method == "GET" and
7269
http.response.status_code in (404, 403)
7370
74-
| eval Esql.url_text = case(url.original is not null, url.original, url.full)
75-
| eval Esql.url_lower = to_lower(Esql.url_text)
71+
| eval Esql.url_original_to_lower = to_lower(url.original)
7672
7773
| keep
7874
@timestamp,
@@ -82,19 +78,19 @@ from logs-network_traffic.http-*, logs-network_traffic.tls-*, logs-nginx.access-
8278
source.ip,
8379
agent.id,
8480
host.name,
85-
Esql.url_lower
81+
Esql.url_original_to_lower
8682
| stats
8783
Esql.event_count = count(),
88-
Esql.url_lower_count_distinct = count_distinct(Esql.url_lower),
84+
Esql.url_original_count_distinct = count_distinct(Esql.url_original_to_lower),
8985
Esql.host_name_values = values(host.name),
9086
Esql.agent_id_values = values(agent.id),
9187
Esql.http_request_method_values = values(http.request.method),
9288
Esql.http_response_status_code_values = values(http.response.status_code),
93-
Esql.url_path_values = values(Esql.url_lower),
89+
Esql.url_original_values = values(Esql.url_original_to_lower),
9490
Esql.event_dataset_values = values(event.dataset)
9591
by source.ip
9692
| where
97-
Esql.event_count > 500 and Esql.url_lower_count_distinct > 250
93+
Esql.event_count > 500 and Esql.url_original_count_distinct > 250
9894
'''
9995

10096
[[rule.threat]]

rules/cross-platform/reconnaissance_web_server_unusual_spike_in_error_logs.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
creation_date = "2025/11/19"
33
integration = ["nginx", "apache", "apache_tomcat", "iis"]
44
maturity = "production"
5-
updated_date = "2025/11/25"
5+
updated_date = "2025/12/01"
66

77
[rule]
88
author = ["Elastic"]
@@ -80,7 +80,7 @@ from logs-nginx.error-*, logs-apache_tomcat.error-*, logs-apache.error-*, logs-i
8080
Esql.event_dataset_values = values(event.dataset)
8181
by source.ip, agent.id
8282
| where
83-
Esql.event_count > 25
83+
Esql.event_count > 50
8484
'''
8585

8686
[[rule.threat]]

rules/cross-platform/reconnaissance_web_server_unusual_spike_in_error_response_codes.toml

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
[metadata]
22
creation_date = "2025/11/19"
3-
integration = ["network_traffic", "nginx", "apache", "apache_tomcat", "iis"]
3+
integration = ["nginx", "apache", "apache_tomcat", "iis"]
44
maturity = "production"
5-
updated_date = "2025/11/24"
5+
updated_date = "2025/12/01"
66

77
[rule]
88
author = ["Elastic"]
@@ -53,10 +53,8 @@ rule_id = "6fa3abe3-9cd8-41de-951b-51ed8f710523"
5353
severity = "low"
5454
tags = [
5555
"Domain: Web",
56-
"Domain: Network",
5756
"Use Case: Threat Detection",
5857
"Tactic: Reconnaissance",
59-
"Data Source: Network Packet Capture",
6058
"Data Source: Nginx",
6159
"Data Source: Apache",
6260
"Data Source: Apache Tomcat",
@@ -66,18 +64,17 @@ tags = [
6664
timestamp_override = "event.ingested"
6765
type = "esql"
6866
query = '''
69-
from logs-network_traffic.http-*, logs-network_traffic.tls-*, logs-nginx.access-*, logs-apache.access-*, logs-apache_tomcat.access-*, logs-iis.access-*
67+
from logs-nginx.access-*, logs-apache.access-*, logs-apache_tomcat.access-*, logs-iis.access-*
7068
| where
71-
(url.original is not null or url.full is not null) and
7269
http.request.method == "GET" and
7370
http.response.status_code in (
7471
500, // Internal Server Error
7572
502, // Bad Gateway
7673
503, // Service Unavailable
7774
504 // Gateway Timeout
7875
)
79-
| eval Esql.url_text = case(url.original is not null, url.original, url.full)
80-
| eval Esql.url_lower = to_lower(Esql.url_text)
76+
77+
| eval Esql.url_original_to_lower = to_lower(url.original)
8178
8279
| keep
8380
@timestamp,
@@ -87,7 +84,7 @@ from logs-network_traffic.http-*, logs-network_traffic.tls-*, logs-nginx.access-
8784
source.ip,
8885
agent.id,
8986
host.name,
90-
Esql.url_lower
87+
Esql.url_original_to_lower
9188
| stats
9289
Esql.event_count = count(),
9390
Esql.http_response_status_code_count = count(http.response.status_code),
@@ -96,7 +93,7 @@ from logs-network_traffic.http-*, logs-network_traffic.tls-*, logs-nginx.access-
9693
Esql.agent_id_values = values(agent.id),
9794
Esql.http_request_method_values = values(http.request.method),
9895
Esql.http_response_status_code_values = values(http.response.status_code),
99-
Esql.url_path_values = values(Esql.url_lower),
96+
Esql.url_path_values = values(Esql.url_original_to_lower),
10097
Esql.event_dataset_values = values(event.dataset)
10198
by source.ip, agent.id
10299
| where

0 commit comments

Comments
 (0)