Skip to content

Commit 23cc251

Browse files
authored
Merge branch 'main' into web-server-esql-rule-tuning
2 parents 7c47c70 + b8aedcd commit 23cc251

17 files changed

+319
-49
lines changed
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
[metadata]
2+
creation_date = "2025/12/02"
3+
integration = ["nginx", "apache", "apache_tomcat", "iis"]
4+
maturity = "production"
5+
min_stack_version = "9.2.0"
6+
min_stack_comments = "The esql url_decode() operator was introduced in version 9.2.0"
7+
updated_date = "2025/12/02"
8+
9+
[rule]
10+
author = ["Elastic"]
11+
description = """
12+
This rule detects potential Local File Inclusion (LFI) activity on web servers by identifying HTTP GET requests that
13+
attempt to access sensitive local files through directory traversal techniques or known file paths. Attackers may
14+
exploit LFI vulnerabilities to read sensitive files, gain system information, or further compromise the server.
15+
"""
16+
from = "now-11m"
17+
interval = "10m"
18+
language = "esql"
19+
license = "Elastic License v2"
20+
name = "Web Server Local File Inclusion Activity"
21+
risk_score = 21
22+
rule_id = "90e4ceab-79a5-4f8e-879b-513cac7fcad9"
23+
severity = "low"
24+
tags = [
25+
"Domain: Web",
26+
"Use Case: Threat Detection",
27+
"Tactic: Discovery",
28+
"Data Source: Nginx",
29+
"Data Source: Apache",
30+
"Data Source: Apache Tomcat",
31+
"Data Source: IIS",
32+
]
33+
timestamp_override = "event.ingested"
34+
type = "esql"
35+
query = '''
36+
from
37+
logs-nginx.access-*,
38+
logs-apache.access-*,
39+
logs-apache_tomcat.access-*,
40+
logs-iis.access-*
41+
| where
42+
http.request.method == "GET" and
43+
http.response.status_code == 200 and
44+
url.original like "*=*"
45+
46+
| eval Esql.url_original_url_decoded_to_lower = to_lower(URL_DECODE(url.original))
47+
48+
| where
49+
/* 1) Relative traversal */
50+
Esql.url_original_url_decoded_to_lower like "*../../../../*" or // Unix-style traversal
51+
Esql.url_original_url_decoded_to_lower like "*..\\\\..\\\\..\\\\..*" or // Windows-style traversal
52+
// Potential security check bypassing (enforcing multiple dots and shortening the pattern)
53+
Esql.url_original_url_decoded_to_lower like "*..././*" or
54+
Esql.url_original_url_decoded_to_lower like "*...\\*" or
55+
Esql.url_original_url_decoded_to_lower like "*....\\*" or
56+
57+
/* 2) Linux system identity / basic info */
58+
Esql.url_original_url_decoded_to_lower like "*etc/passwd*" or
59+
Esql.url_original_url_decoded_to_lower like "*etc/shadow*" or
60+
Esql.url_original_url_decoded_to_lower like "*etc/hosts*" or
61+
Esql.url_original_url_decoded_to_lower like "*etc/os-release*" or
62+
Esql.url_original_url_decoded_to_lower like "*etc/issue*" or
63+
64+
/* 3) Linux /proc enumeration */
65+
Esql.url_original_url_decoded_to_lower like "*proc/self/environ*" or
66+
Esql.url_original_url_decoded_to_lower like "*proc/self/cmdline*" or
67+
Esql.url_original_url_decoded_to_lower like "*proc/self/fd*" or
68+
Esql.url_original_url_decoded_to_lower like "*proc/self/exe*" or
69+
70+
/* 4) Linux webroots, configs & logs */
71+
Esql.url_original_url_decoded_to_lower like "*var/www*" or // generic webroot
72+
Esql.url_original_url_decoded_to_lower like "*wp-config.php*" or // classic WP config
73+
Esql.url_original_url_decoded_to_lower like "*etc/apache2*" or
74+
Esql.url_original_url_decoded_to_lower like "*etc/httpd*" or
75+
Esql.url_original_url_decoded_to_lower like "*etc/nginx*" or
76+
Esql.url_original_url_decoded_to_lower like "*var/log/apache2*" or
77+
Esql.url_original_url_decoded_to_lower like "*var/log/httpd*" or
78+
Esql.url_original_url_decoded_to_lower like "*var/log/nginx*" or
79+
80+
/* 5) Windows core files / identity */
81+
Esql.url_original_url_decoded_to_lower like "*windows/panther/*unattend*" or
82+
Esql.url_original_url_decoded_to_lower like "*windows/debug/netsetup.log*" or
83+
Esql.url_original_url_decoded_to_lower like "*windows/win.ini*" or
84+
Esql.url_original_url_decoded_to_lower like "*windows/system32/drivers/etc/hosts*" or
85+
Esql.url_original_url_decoded_to_lower like "*boot.ini*" or
86+
Esql.url_original_url_decoded_to_lower like "*windows/system32/config/*" or
87+
Esql.url_original_url_decoded_to_lower like "*windows/repair/sam*" or
88+
Esql.url_original_url_decoded_to_lower like "*windows/system32/license.rtf*" or
89+
90+
/* 6) Windows IIS / .NET configs, webroots & logs */
91+
Esql.url_original_url_decoded_to_lower like "*/inetpub/wwwroot*" or
92+
Esql.url_original_url_decoded_to_lower like "*/inetpub/logs/logfiles*" or
93+
Esql.url_original_url_decoded_to_lower like "*applicationhost.config*" or
94+
Esql.url_original_url_decoded_to_lower like "*/microsoft.net/framework64/*/config/web.config*" or
95+
Esql.url_original_url_decoded_to_lower like "*windows/system32/inetsrv/*" or
96+
97+
/* 7) PHP & protocol wrappers */
98+
Esql.url_original_url_decoded_to_lower like "*php://*" or
99+
Esql.url_original_url_decoded_to_lower like "*zip://*" or
100+
Esql.url_original_url_decoded_to_lower like "*phar://*" or
101+
Esql.url_original_url_decoded_to_lower like "*expect://*" or
102+
Esql.url_original_url_decoded_to_lower like "*file://*" or
103+
Esql.url_original_url_decoded_to_lower like "*data://text/plain;base64*"
104+
105+
| keep
106+
@timestamp,
107+
Esql.url_original_url_decoded_to_lower,
108+
source.ip,
109+
agent.id,
110+
host.name,
111+
http.request.method,
112+
http.response.status_code,
113+
event.dataset,
114+
data_stream.namespace
115+
116+
| stats
117+
Esql.event_count = count(),
118+
Esql.url_original_url_decoded_to_lower_count_distinct = count_distinct(Esql.url_original_url_decoded_to_lower),
119+
Esql.host_name_values = values(host.name),
120+
Esql.agent_id_values = values(agent.id),
121+
Esql.http_request_method_values = values(http.request.method),
122+
Esql.http_response_status_code_values = values(http.response.status_code),
123+
Esql.url_original_url_decoded_to_lower_values = values(Esql.url_original_url_decoded_to_lower),
124+
Esql.event_dataset_values = values(event.dataset),
125+
Esql.data_stream_namespace_values = values(data_stream.namespace)
126+
by source.ip
127+
'''
128+
129+
[[rule.threat]]
130+
framework = "MITRE ATT&CK"
131+
132+
[[rule.threat.technique]]
133+
id = "T1083"
134+
name = "File and Directory Discovery"
135+
reference = "https://attack.mitre.org/techniques/T1083/"
136+
137+
[rule.threat.tactic]
138+
id = "TA0007"
139+
name = "Discovery"
140+
reference = "https://attack.mitre.org/tactics/TA0007/"
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
[metadata]
2+
creation_date = "2025/12/02"
3+
integration = ["nginx", "apache", "apache_tomcat", "iis"]
4+
maturity = "production"
5+
min_stack_version = "9.2.0"
6+
min_stack_comments = "The esql url_decode() operator was introduced in version 9.2.0"
7+
updated_date = "2025/12/02"
8+
9+
[rule]
10+
author = ["Elastic"]
11+
description = """
12+
This rule detects potential Remote File Inclusion (RFI) activity on web servers by identifying HTTP GET requests that
13+
attempt to access sensitive remote files through directory traversal techniques or known file paths. Attackers may
14+
exploit RFI vulnerabilities to read sensitive files, gain system information, or further compromise the server.
15+
"""
16+
from = "now-11m"
17+
interval = "10m"
18+
language = "esql"
19+
license = "Elastic License v2"
20+
name = "Web Server Potential Remote File Inclusion Activity"
21+
risk_score = 21
22+
rule_id = "45d099b4-a12e-4913-951c-0129f73efb41"
23+
severity = "low"
24+
tags = [
25+
"Domain: Web",
26+
"Use Case: Threat Detection",
27+
"Tactic: Discovery",
28+
"Tactic: Command and Control",
29+
"Data Source: Nginx",
30+
"Data Source: Apache",
31+
"Data Source: Apache Tomcat",
32+
"Data Source: IIS",
33+
]
34+
timestamp_override = "event.ingested"
35+
type = "esql"
36+
query = '''
37+
from
38+
logs-nginx.access-*,
39+
logs-apache.access-*,
40+
logs-apache_tomcat.access-*,
41+
logs-iis.access-*
42+
| where
43+
http.request.method == "GET" and
44+
http.response.status_code == 200 and
45+
url.original like "*=*"
46+
47+
| eval Esql.url_original_url_decoded_to_lower = to_lower(URL_DECODE(url.original))
48+
49+
| where
50+
Esql.url_original_url_decoded_to_lower like "*=http://*" or
51+
Esql.url_original_url_decoded_to_lower like "*=https://*" or
52+
Esql.url_original_url_decoded_to_lower like "*=ftp://*" or
53+
Esql.url_original_url_decoded_to_lower like "*=smb://*" or
54+
Esql.url_original_url_decoded_to_lower like "*=file://*" or
55+
Esql.url_original_url_decoded_to_lower rlike """.*=.*[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}.*"""
56+
57+
| keep
58+
@timestamp,
59+
Esql.url_original_url_decoded_to_lower,
60+
source.ip,
61+
agent.id,
62+
host.name,
63+
http.request.method,
64+
http.response.status_code,
65+
event.dataset,
66+
data_stream.namespace
67+
68+
| stats
69+
Esql.event_count = count(),
70+
Esql.url_original_url_decoded_to_lower_count_distinct = count_distinct(Esql.url_original_url_decoded_to_lower),
71+
Esql.host_name_values = values(host.name),
72+
Esql.agent_id_values = values(agent.id),
73+
Esql.http_request_method_values = values(http.request.method),
74+
Esql.http_response_status_code_values = values(http.response.status_code),
75+
Esql.url_original_url_decoded_to_lower_values = values(Esql.url_original_url_decoded_to_lower),
76+
Esql.event_dataset_values = values(event.dataset),
77+
Esql.data_stream_namespace_values = values(data_stream.namespace)
78+
by source.ip
79+
'''
80+
81+
[[rule.threat]]
82+
framework = "MITRE ATT&CK"
83+
84+
[[rule.threat.technique]]
85+
id = "T1083"
86+
name = "File and Directory Discovery"
87+
reference = "https://attack.mitre.org/techniques/T1083/"
88+
89+
[rule.threat.tactic]
90+
id = "TA0007"
91+
name = "Discovery"
92+
reference = "https://attack.mitre.org/tactics/TA0007/"
93+
94+
[[rule.threat]]
95+
framework = "MITRE ATT&CK"
96+
97+
[rule.threat.tactic]
98+
id = "TA0011"
99+
name = "Command and Control"
100+
reference = "https://attack.mitre.org/tactics/TA0011/"

rules/cross-platform/initial_access_execution_susp_react_serv_child.toml

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
creation_date = "2025/12/04"
33
integration = ["endpoint", "windows", "auditd_manager", "sentinel_one_cloud_funnel"]
44
maturity = "production"
5-
updated_date = "2025/12/04"
5+
updated_date = "2025/12/05"
66

77
[rule]
88
author = ["Elastic"]
@@ -77,14 +77,43 @@ tags = [
7777
timestamp_override = "event.ingested"
7878
type = "eql"
7979
query = '''
80-
process where event.type == "start" and event.action in ("exec", "executed", "process_started", "start", "ProcessRollup2") and
81-
process.name in ("sh", "bash", "zsh", "curl", "wget", "id", "whoami", "uname", "cmd.exe", "cat", "powershell.exe") and
82-
(
83-
?process.working_directory : ("*react-dom*", "*.next*", "*node_modules/next*", "*react-server*", "*bin/next*", "*--experimental-https*", "*app/server*", "*.pnpm/next*", "*/app/*", "*next/dist/server*", "*react-scripts*") or
84-
85-
(process.parent.name in ("node", "bun", "node.exe", "bun.exe") and
86-
process.parent.command_line : ("*react-dom*", "*.next*", "*node_modules/next*", "*react-server*", "*bin/next*", "*--experimental-https*", "*app/server*", "*.pnpm/next*", "*next start*", "*next dev*", "*react-scripts start*", "*next/dist/server*"))
87-
)
80+
process where event.type == "start" and event.action != "fork" and (
81+
process.name in (
82+
"sh", "bash", "zsh", "curl", "wget", "id", "whoami", "uname", "cmd.exe", "cat", "powershell.exe", "java", "rundll32.exe", "wget.exe", "certutil.exe",
83+
"nc", "ncat", "netcat", "nc.openbsd", "nc.traditional", "socat", "busybox", "mkfifo", "nohup", "setsid", "xterm"
84+
) or
85+
(process.name : "python*" and process.args : "-c" and process.args : (
86+
"*import*pty*spawn*", "*import*subprocess*call*"
87+
)) or
88+
(process.name : "perl*" and process.args : "-e" and process.args : "*socket*" and process.args : (
89+
"*exec*", "*system*"
90+
)) or
91+
(process.name : "ruby*" and process.args : ("-e", "-rsocket") and process.args : (
92+
"*TCPSocket.new*", "*TCPSocket.open*"
93+
)) or
94+
(process.name : "lua*" and process.args : "-e" and process.args : "*socket.tcp*" and process.args : (
95+
"*io.popen*", "*os.execute*"
96+
)) or
97+
(process.name : "php*" and process.args : "-r" and process.args : "*fsockopen*" and process.args : "*/bin/*sh*") or
98+
(process.name == "node" and process.args == "-e" and process.args : "*spawn*sh*" and process.args : "*connect*") or
99+
(process.name : ("awk", "gawk", "mawk", "nawk") and process.args : "*/inet/tcp/*") or
100+
(process.name in ("rvim", "vim", "vimdiff", "rview", "view") and process.args == "-c" and process.args : "*socket*")
101+
)
102+
and (
103+
?process.working_directory : (
104+
"*react-dom*", "*.next*", "*node_modules/next*", "*react-server*", "*bin/next*", "*--experimental-https*", "*app/server*",
105+
"*.pnpm/next*", "*/app/*", "*next/dist/server*", "*react-scripts*") or
106+
(
107+
process.parent.name in ("node", "bun", "node.exe", "bun.exe") and
108+
process.parent.command_line : (
109+
"*react-dom*", "*.next*", "*node_modules/next*", "*react-server*", "*next-server*", "*server.js*", "*bin/next*",
110+
"*--experimental-https*", "*app/server*", "*.pnpm/next*", "*next start*", "*next dev*", "*react-scripts start*", "*next/dist/server*"
111+
)
112+
)
113+
) and not (
114+
?process.parent.executable in ("./runc", "/opt/google/chrome/chrome") or
115+
process.command_line like "/bin/sh -c git config*"
116+
)
88117
'''
89118

90119
[[rule.threat]]

rules/integrations/fim/persistence_suspicious_file_modifications.toml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
creation_date = "2024/06/03"
33
integration = ["fim"]
44
maturity = "production"
5-
updated_date = "2025/01/22"
5+
updated_date = "2025/12/04"
66

77
[rule]
88
author = ["Elastic"]
@@ -21,6 +21,10 @@ name = "Potential Persistence via File Modification"
2121
references = [
2222
"https://www.elastic.co/security-labs/primer-on-persistence-mechanisms",
2323
"https://www.elastic.co/security-labs/sequel-on-persistence-mechanisms",
24+
"https://www.elastic.co/security-labs/continuation-on-persistence-mechanisms",
25+
"https://www.elastic.co/security-labs/approaching-the-summit-on-persistence",
26+
"https://www.elastic.co/security-labs/the-grand-finale-on-linux-persistence",
27+
"https://slayer0x.github.io/awscli/",
2428
]
2529
risk_score = 21
2630
rule_id = "192657ba-ab0e-4901-89a2-911d611eee98"
@@ -94,6 +98,10 @@ file.path : (
9498
"/home/*/.config/fish/config.fish", "/root/.config/fish/config.fish",
9599
"/home/*/.kshrc", "/root/.kshrc",
96100
101+
// Alias files
102+
"/home/*/.bash_aliases", "/root/.bash_aliases", "/home/*/.zsh_aliases", "/root/.zsh_aliases",
103+
"/home/*/.aws/cli/alias", "/root/.aws/cli/alias",
104+
97105
// runtime control
98106
"/etc/rc.common", "/etc/rc.local",
99107

rules/windows/defense_evasion_posh_obfuscation_backtick.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
creation_date = "2025/04/15"
33
integration = ["windows"]
44
maturity = "production"
5-
updated_date = "2025/08/14"
5+
updated_date = "2025/12/01"
66

77
[rule]
88
author = ["Elastic"]
@@ -104,8 +104,7 @@ from logs-windows.powershell_operational* metadata _id, _version, _index
104104
| keep
105105
Esql.script_block_pattern_count,
106106
Esql.script_block_tmp,
107-
powershell.file.script_block_text,
108-
powershell.file.script_block_id,
107+
powershell.file.*,
109108
file.name,
110109
file.directory,
111110
file.path,

rules/windows/defense_evasion_posh_obfuscation_backtick_var.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
creation_date = "2025/04/16"
33
integration = ["windows"]
44
maturity = "production"
5-
updated_date = "2025/07/16"
5+
updated_date = "2025/12/01"
66

77
[rule]
88
author = ["Elastic"]
@@ -103,8 +103,7 @@ from logs-windows.powershell_operational* metadata _id, _version, _index
103103
Esql.script_block_pattern_count,
104104
Esql.script_block_length,
105105
Esql.script_block_tmp,
106-
powershell.file.script_block_text,
107-
powershell.file.script_block_id,
106+
powershell.file.*,
108107
file.path,
109108
file.name,
110109
powershell.sequence,

rules/windows/defense_evasion_posh_obfuscation_char_arrays.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
creation_date = "2025/04/14"
33
integration = ["windows"]
44
maturity = "production"
5-
updated_date = "2025/07/16"
5+
updated_date = "2025/12/01"
66

77
[rule]
88
author = ["Elastic"]
@@ -105,8 +105,7 @@ from logs-windows.powershell_operational* metadata _id, _version, _index
105105
| keep
106106
Esql.script_block_pattern_count,
107107
Esql.script_block_tmp,
108-
powershell.file.script_block_text,
109-
powershell.file.script_block_id,
108+
powershell.file.*,
110109
file.path,
111110
powershell.sequence,
112111
powershell.total,

0 commit comments

Comments
 (0)