任意文件读取与下载漏洞

环境: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);
?>

任意文件读取与下载漏洞_文件名_02

乱码是因为浏览器编码的原因。

读取成功!

file_get_contents()

<?php
$fileName = $_GET['path'];
echo file_get_contents($fileName);
?>

任意文件读取与下载漏洞_白名单_03

打开,读取,关闭!

2、文件读取的攻防

既然读取文件的函数都展现了一遍,按照最特殊的fopen进行攻防讲解

原因既然讲到是对客户输入的路径没有进行过滤,那其实就是对get获取的值进行过滤

思路:读取文件需要什么条件

定位文件位置,用什么定位,就是路径path,路径分为相对路径和绝对路径。

由相对路径来说,就是由本目录为起点,../filename

像本文一样的放在同一目录下只用文件名test.txt就好可是放在别的目录下就会用到../

所以我们过滤掉../不就可以?

先模拟一下真实环境,因为正常情况下,肯定是点击链接去访问某个指定的文件,那我们就在文件顶部加一个<a>标签

<a href = "./fileRead.php?path=test.txt ">111</a>

那点击就会

任意文件读取与下载漏洞_白名单_04

../过滤

之后那我们把新建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,所谓访问不到文件,报错。

任意文件读取与下载漏洞_php_05

由上面的代码可以知道我们只过滤了一遍../,所以双写../就可以绕过,..././
任意文件读取与下载漏洞_文件名_06

所以可以访问!

看下面

$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中)

任意文件读取与下载漏洞_文件名_07

只需将 Option 中的 Indexes 去掉即可

3、让⽤户不能访问Web 根⽬录以外的路径。

在php.ini中设定。

任意文件读取与下载漏洞_php_08

将分号去掉,并等于你想制定只能浏览的目录即可。