11 月 5 日,XLab 披露了一个不太一样的案子。它没有 CVE,因为压根不是漏洞——有人把 CWP(Control Web Panel,以前叫 CentOS Web Panel)的 Web 服务进程 cwpsrv 重新编译了一份,带后门,然后替换掉原文件。

这件事值得写,不是因为手法多新,而是因为它把"运维最信任的那一层"翻过来了。

日志是它自己写的,它选择不记

后门的触发条件很直接:收到一条带 X-Ngx-Integrity-* 系列自定义头的 HTTP 请求,时间戳合法、签名也对得上,就把请求里带的命令以 root 身份执行。

关键在于下一句:这条请求不进 access log。

面板的 Web 服务本身就是日志的生产者。它不写,你在 /usr/local/cwpsrv/logs 里翻到天荒地老也翻不出来。平时我们查入侵,第一反应是"看日志",这一步在这里是空的——不是被清理了,是从来没写过。

文件时间戳也保留原样。ls -l 看不出改动,stat 也看不出。VirusTotal 上 63 个引擎,0 检出。

它不是入口,是二次驻留

投递方式伪装成一次"版本更新":一个叫 cwpsrv_update.sh 的脚本。但所有分析都指向同一个前提——攻击者已经拿到 root 了。

这点得说在前面,不然容易吓错人。它不是"公网面板被打穿"的那一下,而是进来之后留下来的那只手。所以真正要查的是"谁进来的":SSH 登录记录、面板登录、Web 目录里的 webshell、authorized_keys、cron,一样都别漏。

巴西那台受害机器 9 月 30 日把样本传到了 VT。同一个压缩包里还躺着 Ebury 的 libkeyutils.so.1.5.2——XLab 的判断是可能两拨人分别种的。也就是说,一台机器上见到其中一个,另一个也得顺手查。

版本号不能当判据(这条最容易误伤)

雷达最初的写法里有一句"被篡改的版本是 1.15.10 和 1.24.0",我核官方 changelog 之后把它改了。

1.15.10 和 1.24.0 不是什么"中毒版本号",是 CWP 官方自带的 cwpsrv 里那个 nginx 的版本:EL7 上是 1.15.10,EL8/EL9 上是 1.24.0。官方 10 月 31 日的更新日志原文写得很清楚:

cwpsrv updated to nginx 1.30.6 (from 1.24.0 on EL8/EL9 and 1.15.10 on EL7)

按版本号排查,等于把所有正常装机全标成中招。真正的判据只有两个:二进制 md5 跟官方同版本对不上,以及机器上出现了 cwpsrv_update.sh 这种来路不明的"更新脚本"。

顺带说一句,1.30(10/31)、1.30.1(11/3)、1.30.6(11/10)这几版更新日志里,一个字都没提后门这回事。别以为升到最新就洗白了——被换掉的二进制不会因为版本号变了就变回去。

自查

# 1. 二进制指纹:和官方同版本的包比对 md5(最硬的判据)
md5sum /usr/local/cwpsrv/bin/cwpsrv
ls -l --time-style=full-iso /usr/local/cwpsrv/bin/

# 2. 找伪装成更新的投递脚本和可疑残留
find / -xdev \( -name 'cwpsrv_update.sh' -o -name 'cwpsrv.*suspeito*' \
  -o -name 'libkeyutils.so.1.5.2' \) 2>/dev/null

# 3. 后门触发头会不会落在别的日志里(上游 nginx / WAF / 代理)
grep -rIl 'X-Ngx-Integrity' /var/log /usr/local/cwpsrv/logs 2>/dev/null

# 4. 顺手排 Ebury:有没有被替换的 keyutils
rpm -Va 2>/dev/null | grep -i keyutils
dpkg -V 2>/dev/null | grep -i keyutils

处置只有一个方向

没有"修复版本"这种东西。被替换的二进制只能重装:从官方源重新取安装/更新包,别用来路不明的 cwpsrv_update.sh。有条件的,装完跟官方包对一遍 md5,再继续往下用。

这类事情今年不是第一次了。四月那波 apt 中间人换包(那篇在这里)也是同一个逻辑:你信任的那个分发通道,本身就是攻击面。面板类软件更极端一点——CWP、宝塔、aaPanel、Webmin 这些东西天生 root、天生公网、还管着几十个站点,它一旦不可信,下面所有站点的数据库密码、SSH key、邮箱凭据,全都不作数。

上次写 Linux 内核那条 TCP 洞的时候(链接)说过一句:补丁能修的是代码里的错,修不了"你已经信错了一个二进制"。这次也一样。