Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
f070cc2
[Tuning] Extract dynamic field with 1 value to ECS fields for alerts …
Samirbous Jan 16, 2026
c5772ca
Update multiple_alerts_by_host_ip_and_source_ip.toml
Samirbous Jan 16, 2026
d3f5e21
Update newly_observed_elastic_defend_alert.toml
Samirbous Jan 16, 2026
f19865c
Update defense_evasion_base64_decoding_activity.toml
Samirbous Jan 16, 2026
2aa53b0
Update discovery_subnet_scanning_activity_from_compromised_host.toml
Samirbous Jan 16, 2026
3d25d9f
Update persistence_web_server_sus_command_execution.toml
Samirbous Jan 16, 2026
21a184f
Update persistence_web_server_sus_child_spawned.toml
Samirbous Jan 16, 2026
096ca49
Update rules/cross-platform/multiple_alerts_elastic_defend_netsecurit…
Samirbous Jan 20, 2026
fc01c4e
Update rules/linux/impact_potential_bruteforce_malware_infection.toml
Samirbous Jan 20, 2026
9f97143
Update rules/linux/command_and_control_frequent_egress_netcon_from_su…
Samirbous Jan 20, 2026
7b6fef4
Apply suggestions from code review
Samirbous Jan 20, 2026
dc21880
Update rules/cross-platform/multiple_alerts_elastic_defend_netsecurit…
Samirbous Jan 20, 2026
2e7941c
Update rules/cross-platform/newly_observed_elastic_defend_alert.toml
Samirbous Jan 20, 2026
2e97a9f
Update rules/cross-platform/newly_observed_elastic_detection_rule.toml
Samirbous Jan 20, 2026
8d66283
Update rules/windows/credential_access_rare_webdav_destination.toml
Samirbous Jan 20, 2026
940165f
Merge branch 'main' into rules_exception_esql
Samirbous Jan 26, 2026
0948bca
Update credential_access_rare_webdav_destination.toml
Samirbous Jan 26, 2026
81d2f3c
Merge branch 'main' into rules_exception_esql
Samirbous Jan 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[metadata]
creation_date = "2025/12/31"
maturity = "production"
updated_date = "2025/12/31"
updated_date = "2026/01/16"

[rule]
author = ["Elastic"]
Expand Down Expand Up @@ -60,7 +60,11 @@ from .alerts-security.*
| eval concat_ip_values = MV_CONCAT(TO_STRING(Esql.host_ip_values), ",")
| eval host_ip_equal_to_source_ip =LOCATE(concat_ip_values, TO_STRING(Esql.source_ip))
| where Esql.rule_name_distinct_count >= 2 and Esql.host_id_distinct_count >= 2 and host_ip_equal_to_source_ip > 0 and SRC_IP is not null and Esql.alerts_count <= 100
| KEEP Esql.*

// Move signle values to their corresponding ECS fields for alerts exclusion
| eval source.ip = mv_min(Esql.source_ip),
host.id = mv_min(Esql.host_id_values)
| KEEP Esql.*, source.ip, host.id
'''
note = """## Triage and analysis

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
creation_date = "2025/11/18"
integration = ["endpoint", "panw", "fortinet_fortigate", "suricata"]
maturity = "production"
updated_date = "2025/12/30"
updated_date = "2026/01/16"

[rule]
author = ["Elastic"]
Expand Down Expand Up @@ -73,7 +73,13 @@ FROM logs-* metadata _id
| eval concat_module_values = MV_CONCAT(Esql.event_module_values, ",")
// Make sure an endpoint alert is present along one of the network ones
| where concat_module_values like "*endpoint*"
| keep Esql.*

// Move signle values to their corresponding ECS fields for alerts exclusion
| eval source.ip = mv_min(Esql.source_ip),
host.id = mv_min(Esql.host_id_values),
user.name = mv_min(Esql.user_name_values)

| keep source.ip, user.name, Esql.*
'''
note = """## Triage and analysis

Expand Down
10 changes: 7 additions & 3 deletions rules/cross-platform/newly_observed_elastic_defend_alert.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[metadata]
creation_date = "2026/01/05"
maturity = "production"
updated_date = "2026/01/05"
updated_date = "2026/01/16"

[rule]
author = ["Elastic"]
Expand Down Expand Up @@ -33,13 +33,17 @@ from logs-endpoint.alerts-*
Esql.process_parent_executable = VALUES(process.parent.executable),
Esql.process_command_line = VALUES(process.command_line),
Esql.process_hash_sha256 = VALUES(process.hash.sha256),
Esql.host_id = VALUES(host.id),
Esql.host_id_values = VALUES(host.id),
Esql.user_name = VALUES(user.name) by rule.name
// first time seen in the last 5 days - defined in the rule schedule Additional look-back time
| eval Esql.recent = DATE_DIFF("minute", Esql.first_time_seen, now())
// first time seen is within 10m of the rule execution time
| where Esql.recent <= 10 and Esql.agents_distinct_count == 1 and Esql.alerts_count <= 10 and (Esql.last_time_seen == Esql.first_time_seen)
| keep rule.name, Esql.*

// Move signle values to their corresponding ECS fields for alerts exclusion
| eval host.id = mv_min(Esql.host_id_values)

| keep host.id, rule.name, Esql.*
'''
note = """## Triage and analysis

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[metadata]
creation_date = "2026/01/07"
maturity = "production"
updated_date = "2026/01/07"
updated_date = "2026/01/16"

[rule]
author = ["Elastic"]
Expand Down Expand Up @@ -49,7 +49,11 @@ FROM .alerts-security.*
| eval Esql.recent = DATE_DIFF("minute", Esql.first_time_seen, now())
// first time seen is within 10m of the rule execution time
| where Esql.recent <= 10 and Esql.agents_distinct_count == 1 and Esql.alerts_count <= 10 and (Esql.last_time_seen == Esql.first_time_seen)
| keep kibana.alert.rule.name, Esql.*

// Move signle values to their corresponding ECS fields for alerts exclusion
| eval host.id = mv_min(Esql.host_id_values)

| keep host.id, kibana.alert.rule.name, Esql.*
'''
note = """## Triage and analysis

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
creation_date = "2025/02/20"
integration = ["endpoint"]
maturity = "production"
updated_date = "2025/12/17"
updated_date = "2026/01/16"

[rule]
author = ["Elastic"]
Expand Down Expand Up @@ -152,7 +152,14 @@ from logs-endpoint.events.network-* metadata _id, _index, _version
| where
Esql.agent_id_count_distinct == 1 and
Esql.event_count > 15

// Extract unique values to ECS fields for alerts exclusion
| eval agent.id = mv_min(Esql.agent_id_values),
host.name = mv_min(Esql.host_name_values)

| sort Esql.event_count asc

| Keep agent.id, host.name, process.executable, Esql.*
'''

[[rule.threat]]
Expand Down
8 changes: 7 additions & 1 deletion rules/linux/defense_evasion_base64_decoding_activity.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
creation_date = "2025/02/21"
integration = ["endpoint"]
maturity = "production"
updated_date = "2025/12/17"
updated_date = "2026/01/16"

[rule]
author = ["Elastic"]
Expand Down Expand Up @@ -162,6 +162,12 @@ from logs-endpoint.events.process-* metadata _id, _index, _version
Esql.agent_id_count_distinct == 1 and
Esql.event_count < 15
| sort Esql.event_count asc

// Extract unique values to ECS fields for alerts exclusion
| eval agent.id = mv_min(Esql.agent_id_values),
host.name = mv_min(Esql.host_name_values)

| keep agent.id, host.name, process.name, process.command_line, Esql.*
'''

[[rule.threat]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
creation_date = "2025/03/04"
integration = ["endpoint"]
maturity = "production"
updated_date = "2025/12/18"
updated_date = "2026/01/16"

[rule]
author = ["Elastic"]
Expand Down Expand Up @@ -148,6 +148,12 @@ from logs-endpoint.events.network-* metadata _id, _index, _version
Esql.agent_id_count_distinct == 1 and
Esql.destination_port_count_distinct > 100
| sort Esql.event_count asc

// Extract unique values to ECS fields for alerts exclusion
| eval agent.id = mv_min(Esql.agent_id_values),
host.name = mv_min(Esql.host_name_values)

| keep agent.id, host.name, process.executable, destination.ip, Esql.*
'''

[[rule.threat]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
creation_date = "2025/03/04"
integration = ["endpoint"]
maturity = "production"
updated_date = "2025/12/18"
updated_date = "2026/01/16"

[rule]
author = ["Elastic"]
Expand Down Expand Up @@ -139,6 +139,12 @@ from logs-endpoint.events.network-* metadata _id, _index, _version
Esql.agent_id_count_distinct == 1 and
Esql.destination_ip_count_distinct > 250
| sort Esql.event_count asc

// Extract unique values to ECS fields for alerts exclusion
| eval agent.id = mv_min(Esql.agent_id_values),
host.name = mv_min(Esql.host_name_values)

| keep agent.id, host.name, process.executable, Esql.*
'''

[[rule.threat]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
creation_date = "2025/02/21"
integration = ["endpoint"]
maturity = "production"
updated_date = "2025/12/19"
updated_date = "2026/01/16"

[rule]
author = ["Elastic"]
Expand Down Expand Up @@ -160,6 +160,12 @@ from logs-endpoint.events.process-* metadata _id, _index, _version
Esql.agent_id_count_distinct == 1 and
Esql.event_count < 5
| sort Esql.event_count asc

// Extract unique values to ECS fields for alerts exclusion
| eval agent.id = mv_min(Esql.agent_id_values),
host.name = mv_min(Esql.host_name_values)

| keep agent.id, host.name, process.executable, process.parent.executable, Esql.*
'''

[[rule.threat]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
creation_date = "2025/02/20"
integration = ["endpoint"]
maturity = "production"
updated_date = "2025/12/19"
updated_date = "2026/01/16"

[rule]
author = ["Elastic"]
Expand Down Expand Up @@ -152,7 +152,14 @@ from logs-endpoint.events.network-* metadata _id, _index, _version
| where
Esql.agent_id_count_distinct == 1 and
Esql.event_count >= 100

// Extract unique values to ECS fields for alerts exclusion
| eval agent.id = mv_min(Esql.agent_id_values),
host.name = mv_min(Esql.host_name_values)

| sort Esql.event_count asc

| Keep Esql.*, agent.id, host.name, process.executable, destination.port
'''

[[rule.threat]]
Expand Down
8 changes: 7 additions & 1 deletion rules/linux/persistence_web_server_sus_child_spawned.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
creation_date = "2025/03/04"
integration = ["endpoint"]
maturity = "production"
updated_date = "2025/12/23"
updated_date = "2026/01/16"

[rule]
author = ["Elastic"]
Expand Down Expand Up @@ -182,6 +182,12 @@ from logs-endpoint.events.process-* metadata _id, _index, _version
Esql.agent_id_count_distinct == 1 and
Esql.event_count < 5
| sort Esql.event_count asc

// Extract unique values to ECS fields for alerts exclusion
| eval agent.id = mv_min(Esql.agent_id_values),
host.name = mv_min(Esql.host_name_values)

| keep agent.id, host.name, process.executable, process.working_directory, process.parent.executable, Esql.*
'''

[[rule.threat]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
creation_date = "2025/03/04"
integration = ["endpoint"]
maturity = "production"
updated_date = "2025/12/23"
updated_date = "2026/01/16"

[rule]
author = ["Elastic"]
Expand Down Expand Up @@ -167,6 +167,12 @@ from logs-endpoint.events.process-* metadata _id, _index, _version
Esql.agent_id_count_distinct == 1 and
Esql.event_count < 5
| sort Esql.event_count asc

// Extract unique values to ECS fields for alerts exclusion
| eval agent.id = mv_min(Esql.agent_id_values),
host.name = mv_min(Esql.host_name_values)

| keep agent.id, host.name, process.command_line, process.working_directory, process.parent.executable, Esql.*
'''

[[rule.threat]]
Expand Down
12 changes: 9 additions & 3 deletions rules/windows/credential_access_lsass_openprocess_api.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
creation_date = "2023/03/02"
integration = ["endpoint", "m365_defender"]
maturity = "production"
updated_date = "2025/12/11"
updated_date = "2026/01/16"

[transform]
[[transform.osquery]]
Expand Down Expand Up @@ -142,9 +142,15 @@ from logs-endpoint.events.api-*, logs-m365_defender.event-* metadata _id, _versi
Esql.data_stream_namespace.values = VALUES(data_stream.namespace),
Esql.user_name_values = VALUES(user.name) by Esql.process_path

// Limit to rare instances
// Limit to rare instances limited to 1 unique host
| where Esql.count_distinct_hosts == 1 and Esql.access_count <= 3
| keep Esql.*

// Extract the single host ID and process into their corresponding ECS fields for alerts exclusion
| eval host.id = mv_min(Esql.host_id_values),
process.executable = mv_min(Esql.process_path)

// Add the new field to the keep statement
| keep Esql.*, host.id, process.executable
'''


Expand Down
30 changes: 18 additions & 12 deletions rules/windows/credential_access_rare_webdav_destination.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
creation_date = "2025/04/28"
integration = ["endpoint", "system", "windows", "m365_defender", "crowdstrike"]
maturity = "production"
updated_date = "2025/12/05"
updated_date = "2026/01/16"

[rule]
author = ["Elastic"]
Expand Down Expand Up @@ -61,24 +61,30 @@ from logs-endpoint.events.process-*, logs-windows.sysmon_operational-*, logs-sys
event.type == "start" and
process.name == "rundll32.exe" and
process.command_line like "*DavSetCookie*"
| keep host.id, process.command_line, user.name
| grok process.command_line """(?<Esql.server_webdav_cookie>DavSetCookie .* http)"""
| eval
Esql.server_webdav_cookie_replace = replace(Esql.server_webdav_cookie, "(DavSetCookie | http)", "")
| keep host.id, process.command_line, user.name, user.id
| grok process.command_line """(?<Esql.server_webdav_server>([a-zA-Z0-9-]{4,}\.[a-zA-Z]{2,3}@SSL)|((\d{1,3}\.){3}\d{1,3}))"""
| where
Esql.server_webdav_cookie_replace is not null and
Esql.server_webdav_cookie_replace rlike """(([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,3}(@SSL.*)*|(\d{1,3}\.){3}\d{1,3})""" and
not Esql.server_webdav_cookie_replace in ("www.google.com@SSL", "www.elastic.co@SSL") and
not Esql.server_webdav_cookie_replace rlike """(10\.(\d{1,3}\.){2}\d{1,3}|172\.(1[6-9]|2\d|3[0-1])\.(\d{1,3}\.)\d{1,3}|192\.168\.(\d{1,3}\.)\d{1,3})"""
Esql.server_webdav_server is not null and
not Esql.server_webdav_server in ("www.google.com@SSL", "www.elastic.co@SSL", "sharepoint.com@SSL", "live.net@SSL", "google.com@SSL", "SHAREPOINT.COM@SSL", "github.com@SSL") and
not Esql.server_webdav_server rlike """(10\.(\d{1,3}\.){2}\d{1,3}|172\.(1[6-9]|2\d|3[0-1])\.(\d{1,3}\.)\d{1,3}|192\.168\.(\d{1,3}\.)\d{1,3})"""
| stats
Esql.event_count = count(*),
Esql.host_id_count_distinct = count_distinct(host.id),
Esql.user_id_count_distinct = count_distinct(user.id),
Esql.host_id_values = values(host.id),
Esql.user_name_values = values(user.name)
by Esql.server_webdav_cookie_replace
Esql.user_name_values = values(user.name),
by Esql.server_webdav_server

| where
Esql.host_id_count_distinct == 1 and
Esql.event_count <= 3
Esql.event_count <= 3 and Esql.user_id_count_distinct == 1

// Move signle values to their corresponding ECS fields for alerts exclusion
| eval host.id = mv_min(Esql.host_id_values),
user.name = mv_min(Esql.user_name_values),
destination.address = mv_min(Esql.server_webdav_server)

| keep host.id, user.name, destination.address, Esql.*
'''


Expand Down
Loading