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"]
4maturity = "production"
5min_stack_version = "9.2.0"
6min_stack_comments = "The esql url_decode() operator was introduced in version 9.2.0"
7updated_date = "2025/12/08"
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 "Resources: Investigation Guide",
64]
65timestamp_override = "event.ingested"
66type = "esql"
67query = '''
68from
69 logs-nginx.access-*,
70 logs-apache.access-*,
71 logs-apache_tomcat.access-*,
72 logs-iis.access-*
73| where
74 http.request.method == "GET" and
75 http.response.status_code == 200 and
76 url.original like "*=*"
77
78| eval Esql.url_original_url_decoded_to_lower = to_lower(URL_DECODE(url.original))
79
80| where
81 /* 1) Relative traversal */
82 Esql.url_original_url_decoded_to_lower like "*../../../../*" or // Unix-style traversal
83 Esql.url_original_url_decoded_to_lower like "*..\\\\..\\\\..\\\\..*" or // Windows-style traversal
84 // Potential security check bypassing (enforcing multiple dots and shortening the pattern)
85 Esql.url_original_url_decoded_to_lower like "*..././*" or
86 Esql.url_original_url_decoded_to_lower like "*...\\*" or
87 Esql.url_original_url_decoded_to_lower like "*....\\*" or
88
89 /* 2) Linux system identity / basic info */
90 Esql.url_original_url_decoded_to_lower like "*etc/passwd*" or
91 Esql.url_original_url_decoded_to_lower like "*etc/shadow*" or
92 Esql.url_original_url_decoded_to_lower like "*etc/hosts*" or
93 Esql.url_original_url_decoded_to_lower like "*etc/os-release*" or
94 Esql.url_original_url_decoded_to_lower like "*etc/issue*" or
95
96 /* 3) Linux /proc enumeration */
97 Esql.url_original_url_decoded_to_lower like "*proc/self/environ*" or
98 Esql.url_original_url_decoded_to_lower like "*proc/self/cmdline*" or
99 Esql.url_original_url_decoded_to_lower like "*proc/self/fd*" or
100 Esql.url_original_url_decoded_to_lower like "*proc/self/exe*" or
101
102 /* 4) Linux webroots, configs & logs */
103 Esql.url_original_url_decoded_to_lower like "*var/www*" or // generic webroot
104 Esql.url_original_url_decoded_to_lower like "*wp-config.php*" or // classic WP config
105 Esql.url_original_url_decoded_to_lower like "*etc/apache2*" or
106 Esql.url_original_url_decoded_to_lower like "*etc/httpd*" or
107 Esql.url_original_url_decoded_to_lower like "*etc/nginx*" or
108 Esql.url_original_url_decoded_to_lower like "*var/log/apache2*" or
109 Esql.url_original_url_decoded_to_lower like "*var/log/httpd*" or
110 Esql.url_original_url_decoded_to_lower like "*var/log/nginx*" or
111
112 /* 5) Windows core files / identity */
113 Esql.url_original_url_decoded_to_lower like "*windows/panther/*unattend*" or
114 Esql.url_original_url_decoded_to_lower like "*windows/debug/netsetup.log*" or
115 Esql.url_original_url_decoded_to_lower like "*windows/win.ini*" or
116 Esql.url_original_url_decoded_to_lower like "*windows/system32/drivers/etc/hosts*" or
117 Esql.url_original_url_decoded_to_lower like "*boot.ini*" or
118 Esql.url_original_url_decoded_to_lower like "*windows/system32/config/*" or
119 Esql.url_original_url_decoded_to_lower like "*windows/repair/sam*" or
120 Esql.url_original_url_decoded_to_lower like "*windows/system32/license.rtf*" or
121
122 /* 6) Windows IIS / .NET configs, webroots & logs */
123 Esql.url_original_url_decoded_to_lower like "*/inetpub/wwwroot*" or
124 Esql.url_original_url_decoded_to_lower like "*/inetpub/logs/logfiles*" or
125 Esql.url_original_url_decoded_to_lower like "*applicationhost.config*" or
126 Esql.url_original_url_decoded_to_lower like "*/microsoft.net/framework64/*/config/web.config*" or
127 Esql.url_original_url_decoded_to_lower like "*windows/system32/inetsrv/*" or
128
129 /* 7) PHP & protocol wrappers */
130 Esql.url_original_url_decoded_to_lower like "*php://*" or
131 Esql.url_original_url_decoded_to_lower like "*zip://*" or
132 Esql.url_original_url_decoded_to_lower like "*phar://*" or
133 Esql.url_original_url_decoded_to_lower like "*expect://*" or
134 Esql.url_original_url_decoded_to_lower like "*file://*" or
135 Esql.url_original_url_decoded_to_lower like "*data://text/plain;base64*"
136
137| keep
138 @timestamp,
139 Esql.url_original_url_decoded_to_lower,
140 source.ip,
141 agent.id,
142 host.name,
143 http.request.method,
144 http.response.status_code,
145 event.dataset,
146 data_stream.namespace
147
148| stats
149 Esql.event_count = count(),
150 Esql.url_original_url_decoded_to_lower_count_distinct = count_distinct(Esql.url_original_url_decoded_to_lower),
151 Esql.host_name_values = values(host.name),
152 Esql.agent_id_values = values(agent.id),
153 Esql.http_request_method_values = values(http.request.method),
154 Esql.http_response_status_code_values = values(http.response.status_code),
155 Esql.url_original_url_decoded_to_lower_values = values(Esql.url_original_url_decoded_to_lower),
156 Esql.event_dataset_values = values(event.dataset),
157 Esql.data_stream_namespace_values = values(data_stream.namespace)
158 by source.ip
159'''
160
161[[rule.threat]]
162framework = "MITRE ATT&CK"
163
164[[rule.threat.technique]]
165id = "T1083"
166name = "File and Directory Discovery"
167reference = "https://attack.mitre.org/techniques/T1083/"
168
169[rule.threat.tactic]
170id = "TA0007"
171name = "Discovery"
172reference = "https://attack.mitre.org/tactics/TA0007/"
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 Remote File Inclusion Activity
- Potential Spike in Web Server Error Logs
- Web Server Discovery or Fuzzing Activity
- Web Server Potential Command Injection Request
- Web Server Potential Spike in Error Response Codes