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

to-top