Identify and Exploit LFI (Local File Inclusion) Vulnerabilities

by | Dec 1, 2022 | Articles, Write up

Join our Patreon Channel and Gain access to 70+ Exclusive Walkthrough Videos.

Patreon

Reading Time: 8 Minutes

Introduction

As the need to build dynamic web pages, reduce the code/scripts size, and in general speed up the process of creating web pages rises, many web applications use their back-end languages (PHP, JS, Java) along with HTTP parameters to specify and load up their web page content. If such functionalities are not securely/properly coded, a threat actor can manipulate these parameters to steal the content of any local file on the server or even perform a remote code execution, which may result in complete control over the server making the worst-case scenario come to life for every company or organization.

 

Local File Inclusion

Local File Inclusion or Path Traversal vulnerabilities can be used by threat actors to trick a web application into exposing files that are already present on the server by exploiting vulnerable inclusion mechanisms implemented inside the web application.

These kinds of vulnerabilities occur when for example a web application page receives as input, the path to a file that is included in the web page and the input is not properly filtered, thus allowing for local file inclusion exposure or directory traversal characters (../, ….//) to be injected in the URL. The most common place to potentially find an LFI vulnerability is templating engines.

Most web applications today use templating engines to display the static parts of the web page (header, footer) and then dynamically load the content that changes between pages.

An example of such a web application could be a PHP web application which it’s login page URL looks something like this: application.com/index.php/login or application.com/index.php?page=login. The index.php sets the static content and then loads the dynamic content specified in the parameter (login), which in this case is login.php. Because we have control over the login portion of the request, it could be also possible that we can call other files located on the server.

Except for the sensitive information disclosure of the output of the file, these kinds of vulnerabilities can also lead to Remote Code Execution (RCE), Source Code disclosure, Denial of Service (DoS), and XSS attacks.

 

Identifying LFI Vulnerabilities

Since PHP is used among the favorite development frameworks, LFI vulnerabilities are commonly found in PHP-based web applications, however, it can occur in many of the most popular programming languages and development frameworks like .NET, Java, JSP, NodeJS, etc. Every one of them has a distinct approach to including local files, but it all comes down to the mechanism they share(inclusion functions), loading a file from a specified path.

Any web application which has a script that includes a file from a server could be a good candidate to test for LFI vulnerabilities. PHP examples:

vulnerablehost.com/script.php?file=example

vulnerablehost.com/?page=example.php

vulnerablehost.com/user/example.html

It all comes down to how much control an inclusion function gives to the user. Depending on one web application to another, the implementation of such inclusion functions can either be a GET or a POST method.

 

PHP:

In PHP, an inclusion function like the include() function is used to load a local or remote file as the page loads. If the path that the include() function uses is controlled by a user-controlled parameter like GET(HTTP parameter), while the user input is not properly sanitized or filtered, it can lead to potential LFI vulnerabilities:

Code: php
if (isset($_GET[‘file’])) {
include($_GET[‘file’]);
}

In the example above, the parameter file is passed to the include() function. Any path passed in the file parameter will be loaded on the page, like local files on the back-end server. PHP has a lot of functions that can lead to the same vulnerability if control over the path that is passed into them like: require(), file_get_contents(), etc.

 

NodeJS:

As we saw with the PHP example, the same case could be replicated for NodeJS servers which might load content based on HTTP parameters.

Code: javascript
if(req.query.examplefile) {
fs.readFile(path.join(__dirname,
req.query.examplefile), function (err, data) {
res.write(data);
});
}

In the example code above, the GET parameter examplefile is used to show the data on the web page.
The parameter passed from the URL is then used from the readfile function, which then writes the file content in the HTTP response. In such case, we can change the URL to show a different file instead.

It’s always important to keep in mind that some of the inclusion functions will only read the content of the specified files, while others can also execute the specified files. Moreover, some of the functions can also allow specifying remote URLs instead of local ones, which could potentially lead to RFI (remote file inclusion) vulnerabilities.

See Also: So you want to be a hacker?
Offensive Security and Ethical Hacking Course

Exploiting LFI Vulnerabilities

Since LFI vulnerabilities take place when unsanitized/unfiltered paths are passed into include functions, the best approach to find such vulnerabilities is to check for scripts that take filenames as parameters.

For our examples, we will take vulnerablehost.com/script.php?page=example as the path to the vulnerable function, and we will try to fetch the

Note: It’s not necessary that you only enter

“etc/passwd” file path makes sense to use if the vulnerable application runs on a Linux server, trying to view the contents of “etc/passwd” on an application that runs on a Windows ISS server would be fruitless. On Windows, you could try to fetch

file which contains the boot options.

 

Example 1 – Basic Local File inclusion

 

Code: php
include($_GET['example']);

Vulnerable path:
vulnerablehost.com/script.php?file=example

The first thing to do when finding such paths is to check if it can fetch the file we are looking for by adding our file path after “=”.

Exploit:

If the vulnerability exists it will show something like this inside the page:
root:x:0:0:root:/root:/bin/bash

bin:x:1:1:bin:/bin:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

alex:x:500:500:alex:/home/alex:/bin/bash

margo:x:501:501::/home/margo:/bin/bash

<...SNIP…>

 

Example 2 – Local File Inclusion with path traversal

 

Code: php
include("./example/".$_GET['example']);

Vulnerable path:
vulnerablehost.com/script.php?file=example

Using the same technique specifying the absolute path didn’t work for this example. On many occasions developers may append or prepend a string to the file parameter, adding the filename after a directory.

In this case, if we use the same payload

wouldn’t work since the path passed to the include() function would be

This restriction can be bypassed by traversing directories using relative paths. Adding “../” before the file name indicating the parent directory.
If the full path of the example directory is /var/www/html/example, using ../secret.php would refer to the file in the parent directory (/var/www/html/secret.php).

Saying that, we could use this technique to go back several directories until we reach the root path (/), and then add the absolute file path, e.g.

Exploit:

Note: If we are on the root path (/) and still use ../ we would still remain in the root path. If we aren’t sure of the directory we are in, adding more ../ wouldn’t break the path.

 

Example 3 – Local File Inclusion with filename prefix

 

Code: php
include("example-".$_GET['example']);

Vulnerable path:
vulnerablehost.com/script.php?file=example

On some occasions, our input may be appended after a different string (in our example “example-“).
In this case, if we traverse as we did in the earlier example

the final string would be 

which is an invalid file path.

Prefixing a forward slash (/) before our payload would be considered by the web application as a directory, thus, bypassing the appended string allowing us to traverse directories and fetch the file we wanted.

Exploit:

Note: Any prefix appended to the input may break the file inclusion techniques.

Bypassing basic filters:

 

Non-Recursive Path Traversal Filters

A search and replace the filter is one of the most basic filters against LFI, it basically deletes substrings of “../”.
A PHP code that could do that could be:

Code: php
$example=str_replace('../','',$_GET['example']);

This filter is insecure as it does not recursively remove the “../” substring, because it runs a single time on the input string and does not apply the filter on the output string.

A simple bypass of this filter is adding “….//” instead of “../” on our payload. The output of this substring would be “../” since the filter will remove only a portion of the payload (input = ….// ->the”../” is removed according to the filter, resulting in the output = ../ stays). Applying this payload on a web application that uses this filter will bypass it, making traversing directories possible.

 

Encoding

Many web applications deploy filters that cut-off LFI-related characters like dot (.) or forward slash(/).
These filters may be bypassed by URL encoding our payload, such that it would not contain the filtered characters but it would still be decoded back to our path traversal string when it reaches the vulnerable application.
If the application does not allow the filtered characters, by URL encoding the payload from ../ to
%2e%2e%2F could bypass the filtering mechanism.

For convenience you can use the Burp Suite Decoder to encode a string like:

Note: There are many ways to bypass filtering mechanisms, but these basic bypasses can give you an idea of how developers are trying to prevent such vulnerabilities.

 

 

Extending the exploitation of an LFI vulnerability – Source code disclosure with PHP filters

If an LFI vulnerability is identified, we can utilize different PHP Wrappers to extend our exploit.
PHP wrappers can allow to access input/output streams at the application level like input/output, file descriptors, etc., which are primarily used by developers.
These PHP wrappers could be utilized to extend our LFI exploit by being able to perform an RCE on the web application, or even read source code files that may contain sensitive info.

 

PHP Filters

Some types of PHP wrappers are called PHP Filters, where you can pass various types of input and have it filtered by a specific PHP filter.
There are four types of filters, Conversion Filters, String Filters, Encryption Filters, and Compression Filters. To use the PHP filter, we should use the “php://” scheme in our payload string. We can access the PHP filter wrapper with “php://filter/”.
The base64 PHP filter allows to include the local file and base64 encodes the output:

php://filter/convert.base64-encode/resource=example.php

e.g. http://<IP>:<port>/index.php?page=php://filter/convert.base64-encode/resource=example.php

Let’s see how we can use this filter to disclose source code from a vulnerable web application (the example is a lab from Hack the Box -HTB)

 

Source Code disclosure exercise lab on HTB

• We should fuzz the application to find PHP scripts and then read one of the configuration files in order to submit the database password.
• We know that the vulnerable file path is the language.php – /index.php?language=en

  • Fuzzing PHP files:

ffuf -w /opt/useful/SecLists/Discovery/Web-Content/directory-list-2.3-small.txt:FUZZ -u http://<IP>:<Port>/FUZZ.php

Note: We are should not be looking for 200 codes only, but also for 301,302,403 because we are not performing normal web application usage, but we have local file inclusion access.

After the fuzzing on the target is finished, we found some PHP files such as index.php and configure.php.
Saying that, we need to focus the payload around the configure.php file since the password is stored in a configuration file as mentioned in the lab description.

 

• Source code disclosure

The next step is to use the PHP filter to find the contents of the configure.php.
http://134.209.22.69:31344/index.php?language=php://filter/read=convert.base64-encode/resource=configure

As we can see from the screenshot above the source code of the configure.php file is now returned in an encoded string inside the History container. Then, to view the sensitive information we need to decode the string returned.

Echo 'PD9waHAKCmlmICgkX1NFUlZFUlsnUk.. Snip..kue2E' | base64 -d

The php code is not visible in plain text, we can see the contents of the database password and submit the answer for the lab.
Furthermore, the usage of PHP wrappers such as the data wrapper which can be used to include external data such as PHP code and files can even lead in some cases to remote code execution if some particular settings like (allow_url_include) are enabled in the configuration of PHP.

 

 

Prevention

 

LFI/RFI Prevention:

  • The most effective way to eliminate LFI vulnerabilities is to avoid passing any user-submitted input to any filesystem or framework API as the page should dynamically load files on the back-end without any user interaction
  • If the above is not possible, use an allowed list of files that can be included by the page and use identifiers to access the selected files. Also, reject any request that contains invalid identifiers
  • Globally disable the inclusion of remote files
  • Lock web applications to their root directory, preventing access to non-web-related files

 

Path Traversal Prevention:

  • Use your programming language/framework built-int tools to pull only the filename
  • Sanitize user input recursively

 

 

Last Thoughts

We hope that this write-up helps you understand how such attacks can happen, what can go wrong, the impact, and eventually the mitigation of them.

The exploitation of LFI vulnerabilities might cause some serious issues for the target web application varying from information disclosure to complete compromise of the system. Even if the attack does not lead the threat actors to code execution, the valuable information that can be disclosed can still affect the web application and related companies tremendously in various ways.

It’s also important to understand the need to build good coding habits by being aware of how these vulnerabilities are exploited, and how threat actors can bypass the defense mechanisms employed.

Moreover, in order to improve and safeguard our web applications we need to put them into external, third-party testing. By performing external penetration testing along with a source code review, we can be certain that we have an adequate recipe for future success in defending against such attacks.

 

We hope that this write up has taught you something new. If you enjoyed it, the best way that you can support us is to share it! If you’d like to hear more about us, you can find us on LinkedInTwitterYouTube.

 

Are you a security researcher? Or a company that writes articles about Cyber Security, Offensive Security (related to Information Security in general) that match with our specific audience and is worth sharing? If you want to express your idea in an article contact us here for a quote: [email protected]

Merch

Recent Articles

Offensive Security & Ethical Hacking Course

Begin the learning curve of hacking now!


Information Security Solutions

Find out how Pentesting Services can help you.


Join our Community

Share This