An attacker may manipulate parameters used to specify web application resources to display the content of any local file on the hosting server, leading to a Local File Inclusion (LFI).

The most common place LFI is found is in templating engines. Where dynamic content often specified in a parameter of a URL needs to be loaded while other static content is kept the same. If we can change this parameter we may be able to grab other files and display them on the page.

Path Traversal

Often times, web developers may append or prepend a string on a given parameter, in this case if we are trying to execute path traversal we can use relative paths and can add ../ which refers to the parent directory.

Filename Prefix

Our input may be appended after a different string.

include("lang_" . $_GET['language']);

In this case we prefix a / before our payload, and this considers the prefix as a directory and bypasses the filename.

Appended Extensions

include($_GET['language'] . ".php");

Second-Order Attacks

Occurs because many web application functionalities may be insecurely pulling files from the back-end server based on user-controlled parameters.

We usually try and poison a functionality the utilizes this poisoned entry to perform our attack.

Bypasses

Non-Recursive Path Traversal Filters simply delete substrings like ../ to avoid path traversals. Usually these algorithms will run a single on the input string and does not apply the filter on the output string. Using ....// as our payload, would bypass this filter.

We may also just have certain characters like . or / be entirely filtered. We may simply URL encode our ../ into %2e%2e%2f to bypass such filters. This may done twice to double encode our string.

Some web apps specify certain approved paths in the parameter. We can find that path and then append ../ to go back to the root.

Some web applications append an extension to our input, with modern PHP versions we may not be able to bypass. The following techniques are obsolete with versions after PHP 5.4.

Path Truncation

In earlier versions of PHP, defined strings have a maximum length of 4096 characters, if a longer string is passed it will be truncated. PHP also used to remove trailing slashes and single in path names. PHP, and Linux systems in general disregard multiple slashes in the path so with that we can build a payload that ignore the .php extension

?language=non_existing_directory/../../../etc/passwd/./././././ REPEATED ~2048 times]

Null Bytes

In versions before PHP 5.5 we could use null byte injection which means adding a null bytes (%00) at the end of the string to terminate the string and not consider anything after it.

PHP Filters

PHP Wrappers allow us to access different I/O streams at the application level. We can use these to extend our exploitation attacks to be able to read PHP source code or execute commands.

PHP Filters transform stream data by applying specific filters during stream operations. Stream wrappers are accessed via php:// while PHP filter wrapper with php://filter/ to apply filters to a resource. The resource filter wrapper parameter is required and allows us to specify the stream we would like to apply a filter on. read parameter can apply different filters on the input source. The type of filter usually used for LFI attacks is the convert.base64-encode filter under Conversion Filters.

PHP files through LFI will gety executed and rendered as a normal HTML page. This may be useful to access PHP pages we don’t usually have access to but in most cases we want access to the source code. If we base64 encode the php file, and then we transfer the encoded source code instead of having it being executed and rendered.

Here is an example payload

php://filter/read=convert.base64-encode/resource=config

PHP Wrappers

The data wrapper can be used to include external data, including PHP code. This is only possible if the allow_url_include is enabled in the PHP configurations. This option is not enabled by default.

To check if this setting is enabled we can access the PHP configuration file at /etc/php/X.Y/apache2/php.ini for Apache and /etc/php/X.Y/fpm/php.ini.

We can pass this external data in a base64 encoded string with text/plain;base64 and it will decode them and execute the PHP code. Our payload would look like this

data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWyJjbWQiXSk7ID8%2BCg%3D%3D&cmd=id'

The input wrapper can be used to include external input as well and execute the PHP code. input however uses POST requests data, so the vulnerable parameter must accept POST requests for this attack to work. An example payload would be

curl -s -X POST --data '<?php system($_GET["cmd"]); ?>' "http://<SERVER_IP>:<PORT>/index.php?language=php://input&cmd=id"

The expect wrapper allows us to directly run commands through URL streams. It is an external wrapper so it needs to be manually installed and enabled on the back-end server. A payload

curl -s "http://<SERVER_IP>:<PORT>/index.php?language=expect://id"