From local file inclusion to code execution
Local File Inclusion (LFI) is one of the most popular attacks in Information Technology. In this article, we are not going to focus on what LFI attacks are or how we can perform them, but instead, we will see how to gain a shell by exploiting this vulnerability. If you don't know how the attack works, you can have a look here first: File Inclusion Attacks - Infosec.
The main chapters that we will divide this article are:
- Introduction
- From LFI to code execution
- The /proc/self/environ file
- Apache and SSH logs
- Sending emails
- Uploading Files
- Conclusion and Tips
FREE role-guided training plans
From LFI to code execution
As you probably already know, LFI attacks don't only allow attackers to view contents of several files inside a server. With LFI we can sometimes execute shell commands directly to the server. In other words, we can get a shell. Several ways have been developed to achieve this goal. Most of the times, what we should focus on, is:
- Server logs (Apache and SSH).
- Mail logs
- File Upload forms
- The /proc/self/environ file
Every time, we will be trying to inject PHP code inside some server logs to use the LFI attack and thus, execute the code. We will encounter several difficulties, and this is why we will examine multiple techniques. Let's break this down.
For simplicity's sake, we will be using the following PHP code as the vulnerable web application:
<?php
// The page we wish to display
$file = $_GET[ 'page' ];
?>
This implementation can be found at the DVWA project.
Screenshot from the LFI vulnerable app implementation by DVWA.
The /proc/self/environ file
The technique we are going to examine first is the most common method used to gain a shell from an LFI. The file located under /proc/self/environ contains several environment variables such as REMOTE_PORT, HTTP_USER_AGENT and more. For most Linux Operating Systems the file shouldn't be accessible from non-root users. This is why this technique is old and on upgraded systems, it will not work.
Again, on updated systems, we won't be able to access the file from the vulnerable application. Supposing we are dealing with an outdated OS, trying to include the /proc/self/environ file will result in something like this:
For better graphics and user experience I will be using Burp Suite to catch, modify and analyze the requests. The screenshot will be clearer too. Again, here is how it looks like when trying to include the environ file:
As we can see, there is a variable called HTTP_USER_AGENT. This environment variable contains the Web Browser we have used to access the page. On this example, we can see that a Mozilla browser has been used. Of course, we can change our User Agent. As the application will include - execute - this file (and thus our user agent name), we can try to modify our User-Agent to something like:
<?php
system($_GET['cmd']);
?>
For those who are not familiar with PHP, the above command will tell the application to execute (on the server side) whatever follows our new parameter, cmd. Of course, other functions such as exec() or passthru() can be used. To edit the User Agent value, I have used Burp Suite. If you don't want to use Burp, there are several add-ons available which you can use. After sending the malicious request, let's attempt to check if it worked.
By parsing the value ls to the cmd variable, we can see something like this:
Sending a request at [...]/fi/?page=/proc/self/environ&cmd=ls will cause the server to list its files.
As we can see, our attack works! It is now time to get a shell! There are, literally, dozens of ways to do it. View this article and pick one: Reverse Shell Cheat Sheet! My personal opinion is to use the python one. As sometimes nc commands will not be allowed or some of its arguments will be rejected, I have found out that the python one works fine almost every time. My request:
And the result:
As we can see, we have successfully gained a shell by exploiting LFI. That was just one out of the various techniques we can use to achieve it. For the simplicity of this article, I will not repeat the process of gaining a shell again, as you already know how to do it. Instead, we will see several other ways and files you should look for to gain a shell, in case the above technique didn't work.
What should you learn next?
Apache and SSH logs
The Apache and SSH log files are very important, and we should always attempt to inject them if the previous technique has failed. The Apache log file is - most commonly - available under /var/log/apache2/access.log, and it contains all the requests directed to the HTTP server. Here is how the access log file looks like when we attempt to include it.
What we have to do to gain a reverse shell is to create manually an HTTP request with a malicious code included. This malicious code will be then inserted into the apache log file. On our terminal window we can do the following:
Then, by using the LFI to include the /var/log/apache2/access.log file and repeating the process we previously followed, we will be able to gain a shell.
Another tricky way to include malicious code into the logs is by using the SSH logs. These logs are most commonly located under /var/log/auth.log. Whenever we attempt to connect an SSH server, this attempt is logged under the file we mentioned. Thus, if the file is readable we can run something like this:
$ ssh <? php system($_GET['cmd']);?>@VICTIM-IM
Then, we can go back to you web application and attempt to include the /var/log/auth.log file. If the file is readable, we will be able to perform the same actions as before and, as expected, gain a shell!
Sending emails
This is one of the author's favourite ways to move from an LFI to a reverse shell. This technique is one of the simplest and at the same time funniest ways to achieve our goal. All we have to do is to send an email!
A mail server hosts its emails under the /var/mail directory. Every user has a file under this directory with his username set as the filename. Thus, the user www-data will log his emails under /var/log/www-data. Can you imagine what will happen if we send a malicious email to that user and then include the log file via the web application? Let's see!
On this example, we are sending an email with a malicious subject at user "h0r1z0n"
By including the /var/mail/h0r1z0n file (of course, change h0r1z0n with an available user) and by following the previous steps, we will gain a shell again!
Uploading files
This is the easiest method to use. If there is a file upload form and you can upload php files - or bypass the filename security checks - then you can include your uploaded file via the LFI vulnerability as long as you know the uploaded path. Let's see an example.
We create a file called exploit.php. The contents of the file are, as usual:
<?php
system($_GET['cmd']);
?>
For this example, we will be using the DVWA's File Upload challenge. Here is how it looks like:
As we can see, the web application let us know about the upload path. But several times, the web application won't return the upload directory. In this case, we should try to brute force the path or use the standard directories that popular CMS use.
From the LFI vulnerability, we can again execute our commands.
Using the "cat" command to view the /etc/passwd file's contents. Change this command with the on you want to pop a shell! As we mentioned above, I personally prefer the python reverse shell technique.
Conclusion, tips, and references
As you have seen, LFI attacks don't limit our potentials just to file reading. If we think, cleverly we can even get a remote shell to a vulnerable server. Of course, a misconfigured server - i.e., incorrect file access rights - will always help us achieve this goal. Make sure to attempt to access and edit all the available server logs and the files we have previously mentioned. Here are some final tips:
-
Always check the following files:
- /etc/passwd
- /var/log/mail/USER
- /var/log/apache2/access.log
- /proc/self/environ
- /tmp/sess_ID and /var/lib/php5/sess_ID
- Uploaded file path. (if you don't know it checks at /tmp and the default upload paths of every server and CMS). phpinfo() will also help for such information.
- /var/log/auth.log
2) If you can't access the server with any of the previous methods here is a tip:
With LFI you can view the contents of any PHP file you want. You can do this by executing "php://filter/read=convert.base64-encode/resource=FILETOREAD" after the file parameter on the URL. Here is an example:
www.example.com/open.php?file=php://filter/read=convert.base64-encode/resource=../../config.php
Here we can see the contents of the index.php file.
This will return the contents of the index.php file instead of including it - which is the same as executing it. The output will be in Base64 and thus, you will need to decode it. Here is an online decoder: Base64 Decode
After decoding the Base64 version of index.php we can see something like this:
Imagine that there is a configuration file available at the server - e.g., wp-config.php. These files contain several pieces of information - like MySQL ports, database names, and more - but also will include several credentials. You can read their contents and thus, read the credentials!
FREE role-guided training plans
I am sure that there are several other ways to get a shell from an LFI inclusion. Feel free to share them with us in the comments below. If you have any questions, don't hesitate to ask them!