任意文件读取与下载漏洞
环境:windows-s-2008、phpstudy2016、攻击机
成因:
web开放了文件读取及下载的功能(存在读取文件/下载的函数),并且用户端可控制路径,对于用户端输入的路径没有做到完全的过滤。
危害:
1、查看敏感文件;
2、下载源代码做代码审计,查找更多的漏洞;
3、与其他漏洞结合;
1、文件读取的PHP函数
readfile()
file_get_contents()
fopen()
特殊的是fopen()
$fileName = "name.php";
$f = fopen($fileName,‘r‘);#r是读,w是写
echo fread($f,filesize($fileName));
fclose($f); #需要关闭
介绍完特殊的函数我们就开始测试
建立一个fileRead.php文件
然后再建立一个test.txt文件,内容随便
readfile()
<?php
$fileName = $_GET[‘path‘];
readfile($fileName);
?>
乱码是因为浏览器编码的原因。
读取成功!
file_get_contents()
<?php
$fileName = $_GET[‘path‘];
echo file_get_contents($fileName);
?>
打开,读取,关闭!
2、文件读取的攻防
既然读取文件的函数都展现了一遍,按照最特殊的fopen进行攻防讲解
原因既然讲到是对客户输入的路径没有进行过滤,那其实就是对get获取的值进行过滤
思路:读取文件需要什么条件
定位文件位置,用什么定位,就是路径path,路径分为相对路径和绝对路径。
由相对路径来说,就是由本目录为起点,../filename
像本文一样的放在同一目录下只用文件名test.txt就好可是放在别的目录下就会用到../
所以我们过滤掉../不就可以?
先模拟一下真实环境,因为正常情况下,肯定是点击链接去访问某个指定的文件,那我们就在文件顶部加一个<a>
标签
<a href = "./fileRead.php?path=test.txt ">111</a>
那点击就会
../过滤
之后那我们把新建test1.txt(内容为123)文件放到上一级目录下的test文件夹里,所以访问目录就变成了../test/tes1t.txt
后修改代码过滤用str_replace(),将../过滤成空,将
<a href = "./fileRead.php?path=test.txt ">111</a>
<?php
$fileName = $_GET[‘path‘];
$fileName = str_replace("$fileName","../","");
$f = fopen($fileName,"r");
echo fread($f,filesize($fileName));
fclose($f);
?>
因为../test/test1.txt,经过过滤为了test/test1.txt,所谓访问不到文件,报错。
由上面的代码可以知道我们只过滤了一遍../,所以双写../就可以绕过,..././
所以可以访问!
看下面
$file = str_replace( array( "http://", "https://" ), "", $file );
$file = str_replace( array( "../", "..\"" ), "", $file );
所以大家想过滤什么就可以将其添加到数组之中,这是黑名单过滤。
白名单过滤
既然这样可以绕过那我们换一种思路,因为都是访问的都是固定的,那我们就检测访问该文件的文件名是否为我们想让他看的文件。
因为无论是相对路径还是绝对路径,开头必定是../或者C:\,所以我们是不是检测开头是不是我们的文件名就好
<a href = "./fileRead.php?path=test.txt ">111</a>
<?php
$fileName = $_GET[‘path‘];
if($fileName != "test.txt")
{
echo "not found!";
exit;
}
$f = fopen($fileName,"r");
echo fread($f,filesize($fileName));
fclose($f);
?>
拓展:fnamtch函数是检测fileName是否是test开头的字符串,是就返回1,不是0。
这就是白名单过滤,想让谁允许就在if条件语句中添加,这基本就无法绕过了。
3、漏洞修复
1、只让web用户访问指定的文件(上面介绍的白名单)
2、让?户不能访问Web 根?录以外的路径。(在Apache的httpd.conf中)
只需将 Option 中的 Indexes 去掉即可
3、让?户不能访问Web 根?录以外的路径。
在php.ini中设定。
将分号去掉,并等于你想制定只能浏览的目录即可。