「Linux 上不需要杀毒软件」是一种流传很广的说法,而在它最初的意思上是对的:感染 Linux 系统文件的病毒几乎不存在。ClamAV 在服务器上的任务是另一个,可以这样表述:找出通过你的站点被上传进来的东西。首先是 web shell。
我们究竟在找什么
web shell 是一个很小的 PHP 文件,它让人可以通过浏览器执行命令。它经由上传表单、有漏洞的插件或被猜出的管理员密码进来,坐在上传目录里的图片当中,一住就是几个月。防火墙和 Fail2ban 都看不见它:发往它的请求看起来就像发往站点的普通请求。
除此之外 ClamAV 还会找到:
- 用户上传并由你的服务器继续对外提供的恶意文件——服务商的来信通常就是为这个;
- 邮件附件,如果服务器处理邮件的话;
- 文件存储里的 Windows 恶意软件——服务器本身无所谓,但下载了这个文件的员工会遭殃。
关于它的边界先说清楚:ClamAV 不能阻止入侵,也不能自行发现入侵。它发现的是痕迹。一个被巧妙追加到既有主题文件末尾的后门,是会从特征扫描器眼皮底下溜过去的——那正是文件完整性监控存在的意义。
安装,以及唯一真正重要的设置
sudo apt install clamav clamav-daemon
sudo systemctl status clamav-freshclam
第二条命令比第一条更重要。freshclam 是特征库更新服务,如果它没在跑,ClamAV 就会变得毫无用处,同时还继续报告扫描成功。像这样检查库的新旧:
sudo ls -l /var/lib/clamav/*.c?d
sudo freshclam
超过一周的库意味着这个机制坏了。常见原因是外发连接被封,或者 freshclam 曾以 root 身份被手动运行过,此后服务因为权限问题写不进自己的文件。
内存:常驻守护进程还是一次性运行
有两种用法,而这个选择应当是有意识的。
clamd 是常驻的守护进程,把特征库放在内存里。它响应很快,但要占掉大约一个 G 的内存。在一两个 G 的 VPS 上这是不可接受的:守护进程会把数据库和 PHP-FPM 挤出去,服务器开始毫无明显缘由地爬行。用 free -m 和 swap 是否在动来诊断。
替代方案是按计划运行 clamscan。它更慢(每次运行都要加载特征库,约一分钟),但只在扫描期间干活:
sudo clamscan -r -i --exclude-dir='^/(proc|sys|dev|run)' /var/www
-i 这个标志只打印找到的东西;否则输出会长达几十万行。
扫目录,而不是扫整块盘
在一台不强的服务器上全盘扫描要花好几个小时并造成负载,正因如此它被安排到夜里,然后干脆被关掉。更务实的做法是扫描那些真正会从外部改变的地方:
0 3 * * * ionice -c3 nice -n19 clamscan -r -i --move=/var/quarantine /var/www/uploads
这一行里有三处要紧。ionice 和 nice 消除了对站点的影响。用 --move 而不是 --remove——文件进隔离区而不是被删除:误报是会发生的,而被误删的客户文件是从哪儿也找不回来的。而要扫的目录是文件被上传进去的那个,不是根目录。
针对 web shell 的特征
ClamAV 的标准特征库对 PHP 后门是弱项——它们主要面向邮件流量。Linux Malware Detect(maldet)在这方面明显更好:它有一套正是围绕 web shell 构建的特征集,而且在装有 ClamAV 时会用 ClamAV 的引擎去扫。常用的组合就是:ClamAV 当引擎和可更新的特征库,maldet 当专门特征的来源。
找到之后该怎么办
找到一个 web shell 不是调查的终点而是起点。上传目录里出现文件意味着有人能往那里写,而删掉文件并不能消除这个能力。
- 别马上删——保留一份副本,并记下文件的修改时间。
- 用这个时间在 Web 服务器日志里找出是哪个请求把它放进去的。那就是漏洞。
- 找找它的邻居:后门几乎从来不会只留一份。
- 检查同一时间段内磁盘上还有什么变了,以及有没有出现新的 cron 任务和 SSH 密钥。
关于误报要单独说一句。模板库和压缩过的 JavaScript 有时会匹配上特征。正因如此才用隔离而不是删除,也正因如此才有那句建议:别把能找到的每一套第三方特征集都挂上去——一份有一半行是噪声的报告,人们对它的信任一周之内就会消失,然后就不再读它了。
扫描器的实用价值在于它的结果能映入眼帘:上一次扫描是什么时候跑的、特征库有多旧、找到了什么。这就是一行字,但它的缺席会把一个装好的杀毒软件变成一个打钩的形式。这一行是什么样子,见下面的演示页面。