什么是文件包含
简单一句话,为了更好地使用代码的重用性,引入了文件包含函数,可以通过文件包含函数将文件包含进来,直接使用包含文件的代码。
文件包含漏洞成因
在包含文件时候,为了灵活包含文件,将被包含文件设置为变量,通过动态变量来引入需要包含的文件时,用户可以对变量的值可控而服务器端未对变量值进行合理地校验或者校验被绕过,这样就导致了文件包含漏洞。通常文件包含漏洞出现在
PHP
语言中。
PHP文件包含的函数
- include( )
当使用该函数包含文件时,只有代码执行到 include()函数时才将文件包含
进来,发生错误时之给出一个警告,继续向下执行。 - include_once( )
功能与 Include()相同,区别在于当重复调用同一文件时,程序只调用一次 - require( )
require()与 include()的区别在于 require()执行如果发生错误,函数会输出
错误信息,并终止脚本的运行。 - require_once( )
功能与 require()相同,区别在于当重复调用同一文件时,程序只调用一次。
文件包含漏洞分类
- 本地文件包含漏洞
当包含的文件在服务器本地时,就形成了本地文件包含。
下面简单做个测试:
<?php
$file = $_GET['file'];
include($file);
// ......
先说一下文件包含的一个要点:文件包含可以包含任意文件,即便被包含的文件并不是与当前编程语言相关,甚至为图片,只要文件被包含,其内容会被包含文件包含,并以当前服务器脚本语言执行。
可以看到,以上代码中可以控制可控参数file
来控制包含的$file
的值。
- 因此可以建立随意后缀文件进行包含,比如新建文件
file.txt
,文件内容如下:
<?php
phpinfo();
?>
然后包含file.txt
文件:
如果包含的文件内容不符合php语言语法的,会直接将文件内容输出,比如:
- 接下来再看一种情况,开发者限制了包含文件的后缀,代码如下:
<?php
$file = $_GET['file'] . '.php';
echo $file;
include($file);
这样就找不到要包含的文件了,如下:
此时,可以使用%00
截断,不过需要有前提条件:
1). PHP版本 < 5.3 (不包括5.3) ;
2). PHPmagic_quotes_gpc = off
;
3).PHP对所接收的参数,如以上代码的$_GET['file']
未使用addslashes
函数。
因为PHP大于等于5.3的版本已经修复了这个问题,如果开启了gpc
或者使用了addslashes
函数的话则会对其进行转义
首先看php版本小于5.3
,并且magic_quotes_gpc = Off
,1.php
内容如下
<?php
$file = $_GET['file'] . '.php';
echo $file."<br>";
include($file);
phpinfo();
那么我们看magic_quotes_gpc = On
是什么情况呢(效果与使用函数的为一致)
接下来看php版本为5.3
的情况。
可以看到。是没有任何效果的。
总结
对于限制了包含文件后缀的情况,PHP版本小于5.3
,php.inimagic_quotes_gpc = off
,对可控参数未使用addslashes
函数,满足这三个条件就可以使用%00
截断。
那么这两种包含有什么区别呢?其实是没有区别的,原理都一样,只不过第一种是将后缀一起传入,第二种则在程序内固定死了后缀。但是在满足一定条件下可以使用%00
,因为当程序流遇到%00终止符的时候将直接终止。
- 除此之外,还有包含Apache 日志文件。
具体不再讲解,简单直接做一遍一看就懂了。
首先第一步:
此处后来又看到一个骚姿势,开始是访问路径由于url编码原因需要抓包再修改,稍微麻烦,后来看到使用可以直接写进
User Agent
里面也可以被写进日志里,厉害了。
第二步:本地包含日志文件
注意:开始明明php代码写进日志文件里面了,可怎么也包含不成功,弄了好久才发现
httpd
文件夹其他用户没有x
权限,此处记录下哈!
- 远程文件包含漏洞
当包含的文件在远程服务器上时,就形成了远程文件包含。
远程文件包含的注意点:
1). 需要php.ini
中allow_url_include = on
以及allow_url_fopen=on
2). 所包含远程服务器的文件后缀不能与目标服务器语言相同。(比如目标服务器是php脚本语言解析的,那么包含的远程服务器文件后缀不能是php
)
主要解释下第2点:
比如远程服务器文件yuancheng.php
,内容为:
<?php
phpinfo();
?>
再来看下目标服务器的信息
接下来目标服务器包含远程服务器上的文件yuancheng.php
可以看到包含后得到的结果是我们远程机的信息,而不是我们想要的目标机信息。为什么呢?
因为目标服务器包含的代码并不是:
<?php phpinfo();?>
而是而是远程服务器执行完这段代码的源代码,如下图:
所以说远程文件包含只有符合了以上两点才能正常包含。
因此,正确远程包含文件漏洞利用如下:
首先确保配置文件allow_url_fopen = On
以及allow_url_include = On
,如果修改为On记得重启服务
其次,修改文件后缀,只要不是php
就行,比如后缀为.txt
,然后再来包含。
很明显,这次就是我们想要获取的信息了。
接下来就尝试拿webshell了。
文件包含漏洞之伪协议
伪协议在文件包含的利用,本文演示以下伪协议:
data:text/plain
或 data:text/plain;base64
php://input
php://filter
file://
zip://
其它协议可阅读官方文档:传送门
- data:text/plain
直接在对应URL参数内输出:data:text/plain,
,需要执行的php代码 如下图:
这个伪协议还有另一种使用方法,那么就是将需要执行的php代码使用base64编码:data:text/plain;base64,
,需要执行的base64编码后的php代码
如下图:
此处开始在浏览器使用
hackbar
测试不成功,寻其原因,应该是hackbar有问题。
注意:这里base64编码的php代码不能有
;
补充修正:回看写的这个,有问题,不知道之前怎么写的,写了句这话,后经思考应该是<?php phpinfo();?>
base64编码为PD9waHAgcGhwaW5mbygpOz8+
,里面有+
,所以应该是这个原因,故可以写为PD9waHAgcGhwaW5mbygpOz8%2b
即可。
php://input
可以访问请求的原始数据的只读流, 将post请求中的数据作为PHP代码执行。
php://filter
该伪协议可以读取php文件代码以base64编码输出,比如说我们想读取一个php文件但是不想让它正常php执行代码后的结果,我们想要这个php文件的代码的时候就可以使用这个伪协议。
使用方法:php://filter/read=convert.base64-encode/resource=需要读取源码的文件名
- file://
file://
用于访问本地文件系统,且不受allow_url_fopen
与allow_url_include
的影响。
使用方法:file://文件绝对路径 file://C:/Windows/system.ini
- zip://
zip://
可以访问压缩文件中的文件。但是需要绝对路径。
使用方法: zip://[压缩包绝对路径]#[压缩文件内的文件名]
在本地创建一个文件2.php
,并且压缩成2.zip
压缩包,然后包含压缩包里面的文件:
可以看到我已经填写了绝对路径以及文件名称,但是为什么不能成功包含呢,可以看到它的报错Warning: include(zip://E:/soft/phpmystudy/WWW/file_include/2.zip):
我们并不是包含这个压缩包,我们是要包含这个zip里面的文件,为什么#后面的值没了呢,是因为#和URL规则里面的#冲突了,所以我们需要使用编码%23的形式,如下图:
文件包含漏洞防御
- PHP 中使用 open_basedir 配置限制访问在指定的区域
- 过滤.(点)/(反斜杠)\(反斜杠)
- 禁止服务器远程文件包含