Local File Inclusion (LFI) is a type of vulnerability concerning web server. It allow an attacker to include a local file on the web server. It occurs due to the use of not properly sanitized user input.
This can lead to:
- outpouting source code or sensitive information
- code execution (server-side/client-side)
- Denial of service (DoS)
I'll give some examples in PHP but it can also occurs in Perl, ASP, JSP, or whatever.
Here an attacker can simply chose to modify the GET request to give a file that is not in the web serer folder.
Directory traversal attack
Here an attacker can use relative path to get out of the web server folder.
Null Byte Injection
Here the script force to use
.php file extension, but an attacker, by adding a null byte the the path, can drop the extension.
%00 is the http encoded version of
0x00 in hex. It's the null caracter, a null byte. In C it's written
\0 and it means the string termination character so that will stop processing the string immediately.
PHP (like other web server lang) require to process high-level code at system level and it's usually accomplished by using C/C++ functions. Bytes following the delimiter will be ignored.
If in php we have:
In C we have:
so if a null byte is injected int php
Will procude in C:
Go here for more details.
Note: Null byte injection has been fixed in PHP 5.3.4 (unsupported).
Someone aware of previous vulnerabilities may think he will be secure wit a proper filter like:
Bad request (HTTP char encoding):
or bad request (double all chars):
The script replace all
../ with nothing but what if we encode slashs or dotes? or doubling them?
The first method won't work on recent PHP version but the second one will work nearly every times.
Sometimes it's possible to encode some characters of the URL to bypass filters as we have seen previously. This is because the browser decodes the input but PHP does not.
By using double encoding it’s possible to bypass security filters that only decode user input once. The second decoding process is executed by the backend platform or modules that properly handle encoded data, but don't have the corresponding security checks in place.
For example if
urlencode() is used in PHP.
So to continue to bypass the filter a double encoding is needed:
- We encode the data the first time, for example
- And now encode the
As all version of PHP since 5.3.4 are no more vulnerable to null byte injection, we need more methods to bypass extensions filter such as:
- on UNIX
/./etc/passwdis the same as
- on PHP trailing slash are often stripped off so
/etc/passwd/is the same as
- on PHP as trailing slash are stripped off, they can be added as much as we want so
/etc/passwd//////is the same as
- on PHP
./can be appended as many tiems as you want to a path so
/etc/passwd/././.are all the same as
But there is another fact that is interesting to bypass extensions filter: on a lot of PHP installation, filenames longer than 4096 bytes are silently truncated! Characters after the firsts 4096 bytes are discarded and no error is triggered.
So what? Let's craft a very long path to discard
Take your request and append a thousand times
../../../etc/passwd/./././././<...> so will get
../../../etc/passwd/./././././<...>/././.php but the filename will be longer than 4096 bytes so the overlong part will be dropped. So we'll just get our request and thousand times
./ that will be equivalent to
Reverse path truncation
It also exist the reverse version of path truncation. This works by trying to fill the file name from the beginning to exceed the MAX_PATH value.
But this method has a disadvantage: you have to inject the exact number of bytes to truncate only the
.php extension. If too much
../ are injected the filename will also be truncated. Plus, that's why you'll need to add some characters if the path has not the good length because bytes are injected by 3 due to
Details can be found here.
You found a LFI, you included the file but you can't see its content?
Some file like
config.php or libraries of functions are only executed but not shown. So to help us show them, we can use some PHP wrappers.
A famous one is
index.php?page=php://filter/read=convert.base64-encode/resource=config, this filter will encode the page in base64 and show the result like if we have done
index.php?page=config and then base64 it.
A rare but very useful wrapper is
expect://, it allows execution of system commands via php. But it is not enabled by default, an extension needs to be installed.
php://input allows to send payload via POST request.
Post data (uploading a webshell):
Post data (getting server infos):
data:// can be used to include executable PHP code.
Another payload can be
<?php phpinfo(); die();?>, the die statement will prevent the execution of the rest of the script or the execution of the incorrectly decoded extension appended to the stream.
A more usable PHP payload webshell:
To directly execute a command the data request + payload may be:
The best way to successfully execute the payload is to base64 it and then URL encode it.
zip:// and phar://
Archive a php script into a zip or a phar (or others archive with others wrappers), send the archive and tell which file has to be read:
You can append some php code at the end of an image and upload it or include it.
I invite you to discover more attack vectors here.
And don't forget that those methods can be combined.