Nezha 监控系统入侵事件应急响应实录
一次真实的 40 台 VPS 批量入侵事件全记录:从漏洞发现到后门清理、根因定位、复发处置、自动化加固的完整过程。
事件时间:2026-06-19 至 2026-06-20 影响范围:40 台服务器,主控 Nezha dashboard 2.2.3,34 台 agent 被植入后门 事件性质:利用 Nezha 低版本安全漏洞投放持久化后门
一、事件背景
我有 40 台 VPS 分布在多个云服务商(腾讯云、阿里云、华为云、racknerd、netcup、dmit 等),全部接入同一套 Nezha 监控面板。主控部署在腾讯云新加坡(43.156.17.202:8008),运行 dashboard v2.2.3。
2026-06-19,我注意到 Nezha 官方发布了多个安全公告(security advisories),涉及低版本的远程命令执行、路径穿越泄露密钥等严重漏洞。我需要确认:
- 我的 dashboard 和 40 台 agent 是否受影响?
- 攻击者是否已经利用漏洞入侵了我的服务器?
- 如果被入侵了,植入了什么后门?怎么清理?
二、漏洞分析
受影响版本
Nezha 官方安全公告显示,关键修复分界点是 2.2.0:
- Dashboard/Agent
< 2.2.0:受多个中危漏洞影响 - 更老版本叠加高危/严重漏洞
关键 CVE
| GHSA | CVE | 严重性 | 概述 |
|---|---|---|---|
| GHSA-99gv-2m7h-3hh9 | CVE-2026-46716 | 严重 | 低版本 RoleMember 可通过 cron 接口在 Agent 节点执行 shell 命令 |
| GHSA-5c25-7vpj-9mqh | CVE-2026-53519 | 严重 | 低版本 Dashboard 预认证路径穿越泄露 jwt_secret_key |
攻击链路
攻击者获取面板访问权限
├─ 方式1:利用 CVE-2026-53519 路径穿越泄露 jwt_secret_key → 伪造管理员 JWT
├─ 方式2:利用 CVE-2026-46716 cron 接口直接执行命令
└─ 方式3:弱口令 / 泄露的面板账号
↓
通过面板的远程命令能力(cron / terminal / force-update)
在 Agent 节点上执行任意命令
↓
植入持久化后门
三、版本排查
Dashboard 版本
主控 dashboard 是 Docker 部署,版本确认:
docker exec nezha-dashboard /dashboard/app -v
# 输出:2.2.3
dashboard 2.2.3 > 2.2.0,不受 advisory 影响。
Agent 版本(40 台)
这里踩了一个大坑:公开 WebSocket 返回的 host.version 在访客视图下是 null,必须用管理员 JWT 才能看到真实版本。
最终通过以下步骤获取 40 台 agent 版本:
- 从主控 SQLite 数据库读取
jwt_secret_key和未过期 session 的key_id - 用 Go + sqids-go 生成管理员 JWT(Nezha 用 idcodec 对 user_id 做 sqids 编码)
- 用 JWT 连接管理员 WebSocket 读取
host.version
结果:
- 主控 agent:2.2.2(最新)
- 31 台在线 agent:2.2.2(最新)
- 5 台在线 agent:1.9.7(受漏洞影响)
- 4 台离线无版本
5 台旧版 agent:狗云-MG-V6、hostyun-us、绿云-日本大版、狗云-MG-V4、racknerd-DC02。
四、第一轮清理:sysmon 后门
发现
对主控做深度只读检查时,发现 /etc/systemd/system/sysmon.service 和 sysmon-guard.timer,进一步排查发现完整的后门体系:
后门结构:
/usr/local/sysmon/ ← 伪装 Nezha agent 的假二进制 + config.yml
└─ config.yml ← server: 51.254.44.35:8008(攻击者面板)
/usr/local/.sysmon-guard/ ← 守护进程
/usr/local/lib/libsysmon.so ← preload 注入库
/etc/systemd/system/sysmon.service
/etc/systemd/system/sysmon-guard.service
/etc/systemd/system/sysmon-guard.timer ← 30 秒触发自恢复
/etc/ld.so.preload ← 加载 libsysmon.so
后门行为:
- 伪装成
sysmon系统监控服务,实际运行类似 Nezha Agent 的二进制 - 配置文件
server:指向攻击者控制的 Nezha 面板51.254.44.35:8008 sysmon-guard.timer每 30 秒检查一次,如果 sysmon 被杀就重新拉起/etc/ld.so.preload加载libsysmon.so做全局钩子(可能用于隐藏进程/文件)- 日志显示守护进程每 30 秒执行
SELF-HEAL: Re-installing cron
环境变量泄露的后门设计:
STEALTH_NAME=sysmon
INSTALL_DIR=/usr/local/sysmon
GUARD_DIR=/usr/local/.sysmon-guard
LIB_PATH=/usr/local/lib/libsysmon.so
PRELOAD_FILE=/etc/ld.so.preload
清理
清理顺序非常重要(顺序错了守护器会重建文件):
- 停止并禁用
sysmon-guard.timer、sysmon-guard.service、sysmon.service kill -9杀掉所有 sysmon 相关进程- 删除 systemd unit 文件
- 清理
/etc/ld.so.preload中的libsysmon.so引用 - 删除
/usr/local/lib/libsysmon.so - 删除
/usr/local/sysmon和/usr/local/.sysmon-guard目录 systemctl daemon-reload
清理后复查:主控 sysmon 后门已彻底删除,无残留进程/文件/外连。
五、批量清理 40 台
用 paramiko 线程池(10 并发)批量清理所有服务器,密码只在内存中不落盘。
清理结果
- 主控 + 大部分感染节点:sysmon 后门已清理
- 3 台 SSH 超时:raksmart-圣何塞、云曦幻境、geelinx-b,需手动处理
- Agent 版本升级:通过面板
force-updateAPI + 手动 SSH 升级,5 台 1.9.7 升级到 2.2.2
升级 Agent 的坑
force-updateAPI 对disable_force_update: true的 agent 无效- 主控显示旧版本不一定是二进制旧,可能是进程没重启
- 有些机器有多个 nezha-agent 服务,只重启了一个
- hostyun-us 的 IP 从 45.155.222.112 换到了 207.57.137.18
六、复发!发现真正的根因
清理 sysmon 后做全量复查,发现 sysmon 后门 0 复发,但发现了更危险的东西。
第二份 config 后门
34 台服务器的 /opt/nezha/agent/ 目录下,除了合法的 config.yml,还存在随机命名的 config-XXXXX.yml:
| 字段 | 恶意配置 (config-XXXXX.yml) | 合法配置 (config.yml) |
|---|---|---|
| server | 207.58.173.192:8088 | data.nat.tf:8008 (=43.156.17.202) |
| disablecommandexecute | false(远程命令开启) | true(已加固) |
| 文件名 | 随机 5 位后缀 | 无后缀 |
关键证据:
data.nat.tf解析到 43.156.17.202(我的主控),确认config.yml是合法配置207.58.173.192:8088当前无法连接,但配置和进程仍在- 主控上恶意 agent 进程(PID 911,config-etp0h.yml → 207.58.173.192:8088)一直在运行
- 34 台的恶意配置文件名都是随机 5 位后缀,说明是自动化批量投放
为什么这比 sysmon 更危险
| 维度 | sysmon 后门 | 第二份 config 后门 |
|---|---|---|
| 二进制 | 独立假 agent (/usr/local/sysmon) | 合法 nezha-agent |
| 配置 | 独立 config.yml | config-XXXXX.yml 混在合法配置目录 |
| 守护 | sysmon-guard.timer 30 秒 | systemd nezha-agent-XXX.service |
| 注入 | ld.so.preload | 无 |
| 隐蔽性 | 低(独立路径明显) | 高(混在合法 agent 目录里) |
| 命令执行 | 通过 C2 面板 | 通过攻击者 nezha 面板 |
这是真正的复发根因:攻击者不植入独立二进制,而是利用合法 nezha-agent 二进制 + 额外配置文件。即使清理了 sysmon,攻击者仍可通过合法 nezha-agent + 恶意配置维持对 34 台服务器的远程命令执行能力。
七、第二轮清理:第二份 config 后门
清理逻辑
# 1. 找出所有 config-*.yml(带随机后缀的恶意配置)
for cfg in /opt/nezha/agent/config-*.yml; do
# 2. 找对应 service 并停用
for svc in $(systemctl list-units | grep nezha-agent-); do
svc_cfg=$(systemctl cat "$svc" | grep -oE "/opt/nezha/agent/config[^ ]*\.yml")
if [ "$svc_cfg" = "$cfg" ]; then
systemctl stop "$svc"
systemctl disable "$svc"
rm -f "/etc/systemd/system/$svc"
fi
done
# 3. 杀进程
pkill -9 -f "$(basename $cfg .yml)"
# 4. 删配置
rm -f "$cfg"
done
systemctl daemon-reload
# 5. 加固合法 config.yml
sed -i 's/^disable_command_execute:.*/disable_command_execute: true/' /opt/nezha/agent/config.yml
systemctl restart nezha-agent.service
清理结果
- 37 台成功清理:删除 35 个恶意配置 + 35 个恶意服务
- 3 台超时:raksmart-圣何塞、云曦幻境、geelinx-b
- 所有成功清理的服务器:AFTER 状态只剩
config.yml+nezha-agent.service,网络检查全部 CLEAN
八、深度复查
清理后对 40 台服务器做 19 项深度 IOC 扫描:
- sysmon 后门文件
- ld.so.preload 注入
- 第二份 config 后门
- 合法 config 加固状态
- nezha 服务列表
- 挖矿木马进程
- sysmon 相关进程
- 攻击者网络连接
- cron 持久化
- systemd 可疑服务
- SSH authorized_keys
- 登录记录
- SUID 文件
- /tmp 隐藏文件
- 可疑定时器
- CPU 占用
- 异常监听端口
- rc.local/profile.d
- 内核模块
结果
| 检查项 | 结果 |
|---|---|
| sysmon 后门残留 | 0 |
| 第二份 config 后门 | 0 |
| 挖矿木马进程 | 0 |
| 到攻击者面板连接 | 0 |
| ld.so.preload libsysmon | 0 |
| 可疑 cron/systemd | 2 台(腾讯云官方 stargate,已核实非恶意) |
| 完全干净 | 34/36 |
结论:sysmon 后门和第二份 config 后门均无复发,未发现新的木马或黑客遗留。
九、自动化加固
1. 关闭远程命令能力
所有 34 台 nezha 节点的 config.yml 已设置:
disable_command_execute: true # 关闭远程命令执行(terminal/webssh)
disable_nat: true # 关闭 NAT 穿透
2. Dashboard 自动更新(Watchtower)
部署 Watchtower 容器实现 dashboard 自动更新:
docker run -d \
--name watchtower \
--restart always \
-v /var/run/docker.sock:/var/run/docker.sock \
containrrr/watchtower \
--cleanup \
--interval 3600 \
nezha-dashboard
- 每小时检查
ghcr.io/nezhahq/nezha:latest是否有新镜像 - 有新版自动拉取并重启
nezha-dashboard容器 - 只监控 nezha-dashboard,不影响其他容器
- GitHub 发布新版后,最多 1 小时内自动更新,无需手动介入
3. Agent 自动更新
修改 agent 配置:
disable_auto_update: false # 开启自动更新
disable_force_update: false # 允许主控下发强制更新
disable_command_execute: true # 保持远程命令关闭
GitHub 发布新版 agent 后,各节点自动更新,无需手动介入。
十、复发根因分析
后门清理后再次出现,通常是以下原因之一:
- ★第二份 config 后门未清理(最隐蔽):清理了 sysmon 但没检查
config-XXXXX.yml,攻击者通过合法 nezha-agent + 恶意配置维持控制。这是本次事件复发的真正根因。 - 残留自恢复链路:sysmon-guard.timer / cron / ld.so.preload / 隐藏脚本任一残留
- 攻击者仍有登录入口:root 密码、SSH key、面板账号、Agent Secret、JWT Secret 任一泄露
- Nezha 远程命令未及时关闭:低版本暴露期间攻击者拿到面板 token,能继续下发命令
- 同机其他面板漏洞:1Panel / 宝塔 / x-ui / MCSManager / phpMyAdmin / MySQL / Redis 暴露公网
- 清理顺序错误:先删文件没先停守护 → 守护器重建文件
- 密码未轮换:清理后没换 root 密码 / SSH key
十一、经验教训
1. 不要只查一种后门
sysmon 后门特征明显(独立路径 + ld.so.preload),容易发现也容易清理。但第二份 config 后门极隐蔽(合法二进制 + 混在配置目录),清理完 sysmon 后必须复查是否有 config-XXXXX.yml。
2. 清理顺序很重要
停守护 → 杀进程 → 删文件 → 清 ld.so.preload → daemon-reload
顺序错了,守护器会重建文件,等于白清理。
3. Nezha 版本读取的坑
公开 WebSocket 的 host.version 在访客视图下是 null,必须用管理员 JWT 才能看到真实版本。这会导致误判"所有 agent 版本未知",延迟发现旧版节点。
4. Windows SSH 中文路径
Windows 上 OpenSSH 对含中文/空格的私钥路径处理不可靠,必须复制到 ASCII 临时路径 + icacls 收紧 ACL + 用系统自带 C:\Windows\System32\OpenSSH\ssh.exe。
5. 批量操作用 paramiko
系统无 sshpass/expect 时,paramiko 是批量 SSH 的最佳选择。密码只在内存中,绝不落盘。
6. 自动更新很重要
这次事件根因是低版本漏洞被利用。部署 Watchtower + 开启 agent 自动更新后,未来 GitHub 发新版会自动更新,不再需要手动介入。
7. 安全加固清单
- 升级 Dashboard 到最新版(2.2.3)
- 升级所有 Agent 到最新版(2.2.2)
- 清理 sysmon 后门
- 清理第二份 config 后门
- 关闭远程命令执行(disablecommandexecute: true)
- 部署 Watchtower 实现 Dashboard 自动更新
- 开启 Agent 自动更新
- 轮换 root 密码
- 轮换 SSH key
- 轮换 Nezha 面板密码
- 轮换 Agent Secret
- 轮换 JWT Secret
- 关闭非必要公网面板入口
十二、开源工具
本次事件中开发的清理脚本已开源:
- 仓库:https://github.com/motao123/cleanmalwareandhardennezha
- 完整清理脚本:
clean_malware_and_harden_nezha.sh(覆盖三类后门) - 轻量版:
manual_clean_second_config.sh(仅清理第二份 config 后门)
一键使用
curl -fsSL https://raw.githubusercontent.com/motao123/clean_malware_and_harden_nezha/main/clean_malware_and_harden_nezha.sh -o /root/clean.sh
bash /root/clean.sh
群发排查命令
如果你也想检查自己的服务器是否中招:
# sysmon 后门排查
ls -ld /usr/local/sysmon /usr/local/.sysmon-guard /usr/local/lib/libsysmon.so /etc/systemd/system/sysmon* /etc/ld.so.preload 2>/dev/null
# 第二份 config 后门排查
ls /opt/nezha/agent/config-*.yml 2>/dev/null && echo "WARNING: second config backdoor detected"
# 挖矿木马排查
ps auxww | grep -Ei "sysmon|kworker|kdevtmpfsi|kinsing|xmrig" | grep -v grep
# 攻击者连接排查
ss -tnp | grep -E "51.254.44.35|207.58.173.192"
十三、事件时间线
2026-06-19 攻击者利用低版本漏洞植入 sysmon 后门 + 第二份 config 后门
2026-06-20 00:30 发现 Nezha 安全公告,开始排查
2026-06-20 00:45 确认主控 dashboard 2.2.3 不受影响,5 台 agent 为 1.9.7
2026-06-20 00:51 发现主控 sysmon 后门,开始清理
2026-06-20 01:00 sysmon 后门清理完成(主控)
2026-06-20 01:15 批量清理 40 台 sysmon 后门
2026-06-20 01:30 批量升级旧版 agent 到 2.2.2
2026-06-20 02:00 hostyun-us IP 变更,手动修复
2026-06-20 10:25 第一次复发复查:sysmon 0 复发,但发现 34 台第二份 config 后门
2026-06-20 11:00 定位复发根因:第二份 config 后门(config-XXXXX.yml → 207.58.173.192:8088)
2026-06-20 11:47 批量清理第二份 config 后门(37 台成功)
2026-06-20 11:52 更新清理脚本并推送 GitHub
2026-06-20 12:00 深度复查 40 台(19 项检查全部通过)
2026-06-20 12:07 部署 Watchtower + 开启自动更新
2026-06-20 12:13 撰写本文档
总结
这次事件的核心教训:清理了一种后门不等于清理了所有后门。sysmon 后门特征明显容易被发现,但第二份 config 后门利用合法二进制 + 混在配置目录里,隐蔽性极强。如果不是做了深度复查,攻击者仍可通过 34 台服务器的合法 nezha-agent 维持远程命令执行能力。
安全是一个持续的过程,不是一次性的操作。清理后门只是第一步,还需要:升级版本、关闭远程能力、开启自动更新、轮换凭据、关闭非必要公网入口。只有全链路加固,才能避免再次被入侵。
本文档基于真实事件整理,相关清理工具已开源:https://github.com/motao123/cleanmalwareandhardennezha
原文章地址:https://github.com/motao123/cleanmalwareandhardennezha/blob/0772009f3980f8fa3410fe980cd4ab3f3cbd0681/incident-report.md
https://lenghang.com/archives/nezha-jian-kong-xi-tong-ru-qin-shi-jian-ying-ji-xiang-ying-shi-lu