Web Server Local File Inclusion Activity
This rule detects potential Local File Inclusion (LFI) activity on web servers by identifying HTTP GET requests that attempt to access sensitive local files through directory traversal techniques or known file paths. Attackers may exploit LFI vulnerabilities to read sensitive files, gain system information, or further compromise the server.
Elastic rule (View on GitHub)
1[metadata]
2creation_date = "2025/12/02"
3integration = ["nginx", "apache", "apache_tomcat", "iis", "traefik"]
4maturity = "production"
5min_stack_version = "9.3.0"
6min_stack_comments = "Changing min stack to 9.3.0, the latest minimum supported version for 9.X releases."
7updated_date = "2026/09/18"
8
9[rule]
10author = ["Elastic"]
11description = """
12This rule detects potential Local File Inclusion (LFI) activity on web servers by identifying HTTP GET requests that
13attempt to access sensitive local files through directory traversal techniques or known file paths. Attackers may
14exploit LFI vulnerabilities to read sensitive files, gain system information, or further compromise the server.
15"""
16from = "now-11m"
17interval = "10m"
18language = "esql"
19license = "Elastic License v2"
20name = "Web Server Local File Inclusion Activity"
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 Local File Inclusion Activity
27
28This rule surfaces successful GET requests containing directory traversal or direct access to sensitive paths, signaling Local File Inclusion exploitation that can expose credentials, configuration, and process context and enable further compromise. A common attacker pattern is abusing a vulnerable parameter to fetch ../../../../etc/passwd, then pivoting to /proc/self/environ to harvest secrets and identify execution context for subsequent steps.
29
30### Possible investigation steps
31
32- Retrieve contiguous access logs around the alert to rebuild each request/response pair (URI, parameters, user agent, referer, cookies, X-Forwarded-For) and identify which parameter reflected traversal or wrapper usage and whether the response likely contained file contents.
33- Compare response sizes and content-types for the suspicious requests to normal pages and look for signatures such as "root:x:" lines, INI/XML keys, or base64 blobs that indicate disclosure of /etc/passwd, web.config/applicationhost.config, or other sensitive files.
34- Review web server and application error logs at the same timestamps for include/open stream warnings, open_basedir or allow_url_fopen messages, and stack traces to confirm the code path handling the input and any mitigations in place.
35- Pivot on the same source and timeframe to find adjacent probes (php://filter, data://, expect://, zip://, phar://, /proc/self/environ, traversal into webroots/configs) and any follow-on POSTs to upload endpoints or new script paths, signaling progression toward RCE or webshell placement.
36- Determine whether the traffic was authenticated and whether it traversed a WAF or reverse proxy by correlating cookies or session IDs and client IPs with proxy/WAF logs, noting any blocks, rule matches, or bypasses to bound scope and urgency.
37
38### False positive analysis
39
40- A site search or documentation endpoint echoing user-supplied text can include strings like ../../../../etc/passwd, windows/win.ini, or php://filter in the query string and return a normal 200 OK results page rather than performing a file include.
41- An authenticated admin feature (such as a log viewer or file browser) may legitimately accept path= or file= parameters referencing local paths like /var/log/nginx or /inetpub/logs/logfiles and return 200 when serving allowed files, producing URLs that match the rule without exploitation.
42
43### Response and remediation
44
45- Immediately block the source IP at the reverse proxy/WAF and deploy deny rules for GET requests using ../../ or ..\\..\\ traversal or wrappers (php://, expect://, data://) that fetch /etc/passwd, /proc/self/environ, wp-config.php, web.config, or applicationhost.config.
46- Configure the web server to return 403 for paths resolving to /proc, /etc, /var/log, /inetpub, applicationhost.config, and web.config and to reject wrapper schemes like php:// and expect://, then reload Nginx/Apache/IIS to apply.
47- Fix the vulnerable include logic by canonicalizing input with realpath, rejecting any .. segments or absolute paths, enforcing a whitelist of allowed files, and in PHP disabling allow_url_include/allow_url_fopen and setting open_basedir to a safe directory.
48- Rotate exposed secrets by changing database and API credentials from wp-config.php, connection strings and machine keys from web.config/applicationhost.config, and any tokens in /proc/self/environ, then invalidate active sessions and cache.
49- Escalate to incident leadership and quarantine the host if response bodies contain credential patterns (e.g., "root:x:" from /etc/passwd or XML keys from web.config), if /etc/shadow or windows/system32/config/SAM was requested, or if follow-on POSTs or new .php/.aspx files appear in the webroot.
50- Recover by verifying integrity of /var/www and /inetpub/wwwroot, scanning for webshells and unexpected includes, redeploying a known-good build or container image if tampering is found, and adding WAF normalization to double-decode URLs and 403 traversal attempts.
51"""
52risk_score = 21
53rule_id = "90e4ceab-79a5-4f8e-879b-513cac7fcad9"
54severity = "low"
55tags = [
56 "Domain: Web",
57 "Use Case: Threat Detection",
58 "Tactic: Discovery",
59 "Data Source: Nginx",
60 "Data Source: Apache",
61 "Data Source: Apache Tomcat",
62 "Data Source: IIS",
63 "Data Source: Traefik",
64 "Resources: Investigation Guide",
65 "Noise: Medium",
66 "Performance: Fast",
67 "Threat: Web Application Attack",
68 "Rule Type: ES|QL",
69 "Service: Nginx",
70 "Service: IIS",
71 "Service: Apache Tomcat",
72 "Service: Apache HTTP Server",
73]
74timestamp_override = "event.ingested"
75type = "esql"
76query = '''
77from
78 logs-nginx.access-*,
79 logs-apache.access-*,
80 logs-apache_tomcat.access-*,
81 logs-iis.access-*,
82 logs-traefik.access-*
83| where
84 http.request.method == "GET" and
85 http.response.status_code == 200 and
86 url.original like "*=*"
87
88| eval Esql.url_original_url_decoded_to_lower = to_lower(URL_DECODE(url.original))
89
90| where
91 /* 1) Relative traversal */
92 Esql.url_original_url_decoded_to_lower like "*../../../../*" or // Unix-style traversal
93 Esql.url_original_url_decoded_to_lower like "*..\\\\..\\\\..\\\\..*" or // Windows-style traversal
94 // Potential security check bypassing (enforcing multiple dots and shortening the pattern)
95 Esql.url_original_url_decoded_to_lower like "*..././*" or
96 Esql.url_original_url_decoded_to_lower like "*...\\*" or
97 Esql.url_original_url_decoded_to_lower like "*....\\*" or
98
99 /* 2) Linux system identity / basic info */
100 Esql.url_original_url_decoded_to_lower like "*etc/passwd*" or
101 Esql.url_original_url_decoded_to_lower like "*etc/shadow*" or
102 Esql.url_original_url_decoded_to_lower like "*etc/hosts*" or
103 Esql.url_original_url_decoded_to_lower like "*etc/os-release*" or
104 Esql.url_original_url_decoded_to_lower like "*etc/issue*" or
105
106 /* 3) Linux /proc enumeration */
107 Esql.url_original_url_decoded_to_lower like "*proc/self/environ*" or
108 Esql.url_original_url_decoded_to_lower like "*proc/self/cmdline*" or
109 Esql.url_original_url_decoded_to_lower like "*proc/self/fd*" or
110 Esql.url_original_url_decoded_to_lower like "*proc/self/exe*" or
111
112 /* 4) Linux webroots, configs & logs */
113 Esql.url_original_url_decoded_to_lower like "*var/www*" or // generic webroot
114 Esql.url_original_url_decoded_to_lower like "*wp-config.php*" or // classic WP config
115 Esql.url_original_url_decoded_to_lower like "*etc/apache2*" or
116 Esql.url_original_url_decoded_to_lower like "*etc/httpd*" or
117 Esql.url_original_url_decoded_to_lower like "*etc/nginx*" or
118 Esql.url_original_url_decoded_to_lower like "*var/log/apache2*" or
119 Esql.url_original_url_decoded_to_lower like "*var/log/httpd*" or
120 Esql.url_original_url_decoded_to_lower like "*var/log/nginx*" or
121
122 /* 5) Windows core files / identity */
123 Esql.url_original_url_decoded_to_lower like "*windows/panther/*unattend*" or
124 Esql.url_original_url_decoded_to_lower like "*windows/debug/netsetup.log*" or
125 Esql.url_original_url_decoded_to_lower like "*windows/win.ini*" or
126 Esql.url_original_url_decoded_to_lower like "*windows/system32/drivers/etc/hosts*" or
127 Esql.url_original_url_decoded_to_lower like "*boot.ini*" or
128 Esql.url_original_url_decoded_to_lower like "*windows/system32/config/*" or
129 Esql.url_original_url_decoded_to_lower like "*windows/repair/sam*" or
130 Esql.url_original_url_decoded_to_lower like "*windows/system32/license.rtf*" or
131
132 /* 6) Windows IIS / .NET configs, webroots & logs */
133 Esql.url_original_url_decoded_to_lower like "*/inetpub/wwwroot*" or
134 Esql.url_original_url_decoded_to_lower like "*/inetpub/logs/logfiles*" or
135 Esql.url_original_url_decoded_to_lower like "*applicationhost.config*" or
136 Esql.url_original_url_decoded_to_lower like "*/microsoft.net/framework64/*/config/web.config*" or
137 Esql.url_original_url_decoded_to_lower like "*windows/system32/inetsrv/*" or
138
139 /* 7) PHP & protocol wrappers */
140 Esql.url_original_url_decoded_to_lower like "*php://*" or
141 Esql.url_original_url_decoded_to_lower like "*zip://*" or
142 Esql.url_original_url_decoded_to_lower like "*phar://*" or
143 Esql.url_original_url_decoded_to_lower like "*expect://*" or
144 Esql.url_original_url_decoded_to_lower like "*file://*" or
145 Esql.url_original_url_decoded_to_lower like "*data://text/plain;base64*"
146
147| keep
148 @timestamp,
149 Esql.url_original_url_decoded_to_lower,
150 source.ip,
151 agent.id,
152 agent.name,
153 http.request.method,
154 http.response.status_code,
155 data_stream.dataset,
156 data_stream.namespace
157
158| stats
159 Esql.event_count = count(),
160 Esql.url_original_url_decoded_to_lower_count_distinct = count_distinct(Esql.url_original_url_decoded_to_lower),
161 Esql.agent_name_values = values(agent.name),
162 Esql.agent_id_values = values(agent.id),
163 Esql.http_request_method_values = values(http.request.method),
164 Esql.http_response_status_code_values = values(http.response.status_code),
165 Esql.url_original_url_decoded_to_lower_values = values(Esql.url_original_url_decoded_to_lower),
166 Esql.data_stream_dataset_values = values(data_stream.dataset),
167 Esql.data_stream_namespace_values = values(data_stream.namespace)
168 by source.ip
169'''
170
171[[rule.threat]]
172framework = "MITRE ATT&CK"
173
174[[rule.threat.technique]]
175id = "T1083"
176name = "File and Directory Discovery"
177reference = "https://attack.mitre.org/techniques/T1083/"
178
179[rule.threat.tactic]
180id = "TA0007"
181name = "Discovery"
182reference = "https://attack.mitre.org/tactics/TA0007/"
183
184[[rule.threat]]
185framework = "MITRE ATT&CK"
186
187[[rule.threat.technique]]
188id = "T1005"
189name = "Data from Local System"
190reference = "https://attack.mitre.org/techniques/T1005/"
191
192[rule.threat.tactic]
193id = "TA0009"
194name = "Collection"
195reference = "https://attack.mitre.org/tactics/TA0009/"
196
197[[rule.threat]]
198framework = "MITRE ATT&CK"
199
200[[rule.threat.technique]]
201id = "T1552"
202name = "Unsecured Credentials"
203reference = "https://attack.mitre.org/techniques/T1552/"
204
205[[rule.threat.technique.subtechnique]]
206id = "T1552.001"
207name = "Credentials In Files"
208reference = "https://attack.mitre.org/techniques/T1552/001/"
209
210[rule.threat.tactic]
211id = "TA0006"
212name = "Credential Access"
213reference = "https://attack.mitre.org/tactics/TA0006/"
214
215[[rule.threat]]
216framework = "MITRE ATT&CK"
217
218[[rule.threat.technique]]
219id = "T1190"
220name = "Exploit Public-Facing Application"
221reference = "https://attack.mitre.org/techniques/T1190/"
222
223[rule.threat.tactic]
224id = "TA0001"
225name = "Initial Access"
226reference = "https://attack.mitre.org/tactics/TA0001/"
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 Local File Inclusion Activity
This rule surfaces successful GET requests containing directory traversal or direct access to sensitive paths, signaling Local File Inclusion exploitation that can expose credentials, configuration, and process context and enable further compromise. A common attacker pattern is abusing a vulnerable parameter to fetch ../../../../etc/passwd, then pivoting to /proc/self/environ to harvest secrets and identify execution context for subsequent steps.
Possible investigation steps
- Retrieve contiguous access logs around the alert to rebuild each request/response pair (URI, parameters, user agent, referer, cookies, X-Forwarded-For) and identify which parameter reflected traversal or wrapper usage and whether the response likely contained file contents.
- Compare response sizes and content-types for the suspicious requests to normal pages and look for signatures such as "root:x:" lines, INI/XML keys, or base64 blobs that indicate disclosure of /etc/passwd, web.config/applicationhost.config, or other sensitive files.
- Review web server and application error logs at the same timestamps for include/open stream warnings, open_basedir or allow_url_fopen messages, and stack traces to confirm the code path handling the input and any mitigations in place.
- Pivot on the same source and timeframe to find adjacent probes (php://filter, data://, expect://, zip://, phar://, /proc/self/environ, traversal into webroots/configs) and any follow-on POSTs to upload endpoints or new script paths, signaling progression toward RCE or webshell placement.
- Determine whether the traffic was authenticated and whether it traversed a WAF or reverse proxy by correlating cookies or session IDs and client IPs with proxy/WAF logs, noting any blocks, rule matches, or bypasses to bound scope and urgency.
False positive analysis
- A site search or documentation endpoint echoing user-supplied text can include strings like ../../../../etc/passwd, windows/win.ini, or php://filter in the query string and return a normal 200 OK results page rather than performing a file include.
- An authenticated admin feature (such as a log viewer or file browser) may legitimately accept path= or file= parameters referencing local paths like /var/log/nginx or /inetpub/logs/logfiles and return 200 when serving allowed files, producing URLs that match the rule without exploitation.
Response and remediation
- Immediately block the source IP at the reverse proxy/WAF and deploy deny rules for GET requests using ../../ or ....\ traversal or wrappers (php://, expect://, data://) that fetch /etc/passwd, /proc/self/environ, wp-config.php, web.config, or applicationhost.config.
- Configure the web server to return 403 for paths resolving to /proc, /etc, /var/log, /inetpub, applicationhost.config, and web.config and to reject wrapper schemes like php:// and expect://, then reload Nginx/Apache/IIS to apply.
- Fix the vulnerable include logic by canonicalizing input with realpath, rejecting any .. segments or absolute paths, enforcing a whitelist of allowed files, and in PHP disabling allow_url_include/allow_url_fopen and setting open_basedir to a safe directory.
- Rotate exposed secrets by changing database and API credentials from wp-config.php, connection strings and machine keys from web.config/applicationhost.config, and any tokens in /proc/self/environ, then invalidate active sessions and cache.
- Escalate to incident leadership and quarantine the host if response bodies contain credential patterns (e.g., "root:x:" from /etc/passwd or XML keys from web.config), if /etc/shadow or windows/system32/config/SAM was requested, or if follow-on POSTs or new .php/.aspx files appear in the webroot.
- Recover by verifying integrity of /var/www and /inetpub/wwwroot, scanning for webshells and unexpected includes, redeploying a known-good build or container image if tampering is found, and adding WAF normalization to double-decode URLs and 403 traversal attempts.
Related rules
- Web Server Potential Command Injection Request
- Web Server Potential Remote File Inclusion Activity
- Web Server Suspicious User Agent Requests
- Web Server Discovery or Fuzzing Activity
- Web Server Potential Spike in Error Response Codes