Introduction to Local File Inclusions
File inclusions are part of every advanced server side scripting language on the web. They are needed to keep web applications' code tidy and maintainable. They also allow web applications to read files from the file system, provide download functionality, parse configuration files and do other similar tasks. Though if not implemented properly, they can become an exploitable web vulnerability which malicious attackers can take advantage of.
How do Local File Inclusions Work?
Usually the path of the file you want to open is sent to a function which returns the content of the file as a string, or prints it on the current web page, or includes it into the document and parses it as part of the respective language.
Typical Scenarios Where Local File Inclusions Are Used and Their Risks
Scenario 1: Including Files to be Parsed by the Language's Interpreter
To keep a website's code readable and modular the code is usually split into multiple files and directories, ideally separated into logical pieces. To tell the interpreter where those files are you have to specify a correct file path and pass it to a function. This function will open the file and include it inside the document. This way the parser sees it as valid code and interprets it accordingly.
You create several different modules for one page and to include them you use the GET parameter with the filename of the respective function, such as:
The Risks of Introducing a Local File Inclusion Vulnerability
If the developer failes to implement sufficient filtering an attacker could exploit the local file inclusion vulnerability by replacing contact.php with the path of a sensitive file, which will be parsed and the attacker can see its content, such as:
In such scenario the malicious hacker could also inject code from somewhere else on the web server and let the parser interpret it as instructions to exploit the LFI vulnerability. A good way to do that is a picture upload functionality with an image containing malicious code in its source, such as:
Scenario 2: Including Files that are Printed to a Page
Sometimes you need the output of a file to be shared across different web pages, for example a header. file This comes in handy especially if you want the changes of such file to be reflected on all the pages where it is included. Such file could be plain html and does not have to be interpreted by any parser on the server side. Though it can also be used to show other data such as simple text files.
You have a collection of .txt files with help texts and want to make them available through a web application. These files are reachable through a link such as:
In this scenario the content of the text file will be printed directly to the page without using a database to store the information.
The Risks of Introducing a Local File Inclusion Vulnerability
If no proper filtering is implemented, an attacker could change the link to something such as
https://example.com/?helpfile=../secret/.htpasswd to retrieve the password hashes of a .htpasswd file, which typically contains the credentials of all users that have access to restricted areas of the webserver.
The attacker might also be able to access and read the content of other hidden configuration files containing passwords and other sensitive information.
Scenario 3: Including Files that are Served as Downloads
Some files are automatically opened by web browsers when accessed, such as PDF files. If you want to serve files as downloads instead of showing them in the browser window you have to add an additional header instructing the browser to do so. You can include the header Content-Disposition: attachment; filename=file.pdf in the request and the browser will download the files instead of opening them.
You have the company brochures in pdf format and the web application visitors use this link to download them:
The Risks of Introducing a Local File Inclusion (LFI) Vulnerability
If there is no sanitization of the request, the attacker could request the download of files that make up the web application, therefore being able to read the source code and possible find other web application vulnerabilities or read sensitive file contents. For example the attacker can use the same function to read the source code of the file connection.php:
If the attacker finds the database user, host and password he can connect to the database remotely with the stolen credentials. At this stage the malicious hacker can execute database commands and compromise the web server if the database user has file write privileges.
Impacts of an Exploited Local File Inclusion Vulnerability
As shown above, the impacts of exploiting a Local File Inclusion (LFI) vulnerability vary from information disclosure to complete compromise of the system. Even in cases where the included code is not executed, it can still give an attacker enough valuable information to be able to compromise the system. Even though old ways of exploiting the first scenario won't work anymore on most modern systems, e.g. including the access.log file, there are still some methods that can still lead to a complete system compromise through evaluated script code.
Peventing Local File Inclusion Vulnerabilities in Your Web Applications
Tips for Letting Users Read or Download Files Securely
- Save the file paths in a database and assign an ID to each of them. BY doing so users only see the ID and are not able to view or change the path.
- Use a whitelist of filenames and ignore every other filename and path.
- Instead of including files on the web server, store their content in databases where possible.
- Instruct the server to automatically send download headers and not execute files in a specific directory such as /download/. That way you can point the user directly to the file on the server without having to write additional code for the download. An example link could look like
What You Should NOT Do to Avoid LFI Vulnerabilities
- Blacklisting filenames; attackers have a variety of filenames to include for information disclosure or code execution. Maintaining such a list is practically not possible. It also is not enough to blacklist files commonly used for testing against LFI like /etc/passwd or /etc/hosts
- Removing or blacklisting character sequences. There are known bypasses for removing or blacklisting those.
- Encoding the file path with base64, bin2hex or similar functions as this can be reversed relatively easily by an attacker.