Local and Remote File Inclusion: Path Traversal and How to Stop It
File inclusion vulnerabilities occur when an application uses user-supplied input to decide which file to load. The intended behaviour is selecting a template or a language file from a fixed set; the actual behaviour, when the input is not constrained, is loading whatever the attacker names.
Local file inclusion
LFI reads files already present on the server. A parameter meant to select a page instead receives a path with traversal sequences — ../ repeated enough times to climb out of the intended directory and then descend to something interesting.
Standard targets tell you a lot about a system: the password file and user list, application configuration files containing database credentials and API keys, environment files, private keys, and log files. On Linux, the process filesystem exposes environment variables and command lines for running processes, which frequently contain secrets passed at startup.
Even without code execution this is a serious finding. Configuration files typically hold the credentials that lead to the next stage, and source code disclosure hands the attacker a map of everything else.
Remote file inclusion
RFI loads a file from a URL the attacker controls, so attacker-supplied code is fetched and executed directly. It is far more severe and far rarer, because the language configuration that permits it has been off by default for many years.
When a scenario describes including a file from a remote server, it is RFI; when it describes reading a local file through traversal, it is LFI. That distinction is what exam questions turn on.
Escalating from read to execute
The interesting part of LFI is that a file read often becomes code execution, and understanding the mechanism explains why the vulnerability is rated as highly as it is.
Log poisoning is the classic route. The attacker sends a request whose user agent or requested path contains code, the web server writes that string into its access log, and the attacker then includes the log file. The application interprets it, and the code runs.
Similar tricks target session files, uploaded files whose content is controlled even when the extension is not, and mail spool files. In each case the attacker gets content of their choosing onto disk by legitimate means, then uses the inclusion flaw to have it interpreted.
Language-specific wrappers make this easier still, allowing encoded data or filters to be passed where a filename was expected — which is why blocking ../ alone is not a defence.
Why filtering fails
The instinctive fix is to strip ../ from input. It does not hold.
A naive single-pass strip can be defeated by nesting the sequence so removal reassembles it. URL encoding, double encoding, and alternative encodings produce the same path in forms a simple string match misses. Absolute paths skip traversal entirely. Null byte truncation worked for years against implementations that appended an extension.
This is the general lesson about blocklists: you are trying to enumerate every representation of badness against an attacker who only needs one you missed.
What actually works
Do not put user input in file paths. Where the application chooses between a known set of files, map the input to an identifier and look up the real path in a server-side table. The user sends page=about and the code looks up which file that means. There is no path to traverse because no path came from the user.
Where a path is unavoidable, validate against an allowlist of permitted values, then canonicalize the resulting path — resolve it fully — and confirm the result is still inside the intended directory. Canonicalize before checking, never after, or the check inspects a string that is not what will be opened.
Limit the damage. Run the application as a low-privileged account that cannot read system files or other applications' data. Disable remote file inclusion in the language configuration. Keep secrets out of files the web process can read, and out of environment variables where the process filesystem exposes them.
A WAF blocks common traversal payloads and buys time, and like every filter in front of a defect it is not the repair — the same position taken on SQL injection, and for the same reason: the flaw is that untrusted input reached a place where it is interpreted.
Detection
Traversal sequences in request parameters are easy to alert on, in raw and encoded forms. Requests for known sensitive filenames, and application errors mentioning file-not-found with unusual paths, are the other signals. Feed web server logs into your SIEM and watch for a single source probing many parameter values — the enumeration is noisy even when the successful request is not.
Exam angles
Define LFI as including a local file through unvalidated input, typically with path traversal, and RFI as including a remote attacker-controlled file. Know that LFI can escalate to code execution through log poisoning or uploaded content. Recognize that filtering traversal sequences is bypassable through encoding and nesting, and that mapping input to an allowlist of identifiers, plus canonicalizing and verifying the final path, is the correct control.
Comments
Post a Comment