漏洞公告里那句「更新不能修复已经发生的入侵」,是整份公告里最容易被跳过、也最贵的一句话。

升级把漏洞门关上了,但如果此前已经被利用,门里留下的东西还在。PHP2Shell 的利用结果是远程代码执行——拿到执行权限的攻击者,做的第一件事通常就是在 Web 目录里放一个 webshell。

一、先划定排查窗口

窗口的起点有两个候选,取更早的那个:

  • 2026-10-21:官方发布修复版,PoC 开始广泛传播。
  • 更早:如果你的站点此前已经存在其他可被利用的弱点,攻击者可能更早就在试探。

窗口的终点是现在——因为清理和凭据轮换都需要时间,排查不能只做一次。

二、五类痕迹,逐项排查

1. 访问日志:攻击者尝试过什么

PHP2Shell 的特征是超大请求体。在访问日志与 WAF 日志里找:

  • POST 请求体异常巨大(远大于业务正常值)的请求;
  • 同一时间窗内大量 500、502、503 与 worker 重启;
  • 针对不存在的路径的探测:/.env、/.git、/wp-admin、/actuator、/vendor/phpunit 等;
  • 异常的 User-Agent 串、空 UA、扫描器特征;
  • 来自同一批 IP 的密集请求——注意区分真实爬虫与扫描器。

2. FPM 与 PHP 错误日志:worker 崩过没有

这条漏洞的确认形态之一是 worker 崩溃(use-after-free)。日志里的 Segfault、child exited、worker 异常重启突然增多,是强烈信号。同时看 PHP 错误日志里的 OOM 记录、Allowed memory size exhausted 是否有异常尖峰。

3. 文件系统:webshell 在哪

这是最关键的一步。重点排查:

  • Web 根目录及其子目录中新增或修改的 PHP 文件,尤其是文件名看起来随机的(.php 藏在图片目录里、带后门特征函数如 assert、base64_decode、eval、preg_replace 带 /e 的组合);
  • 文件修改时间落在窗口期内的所有文件,用 find 按时间筛一遍:
# 窗口期内新增/修改的所有文件
find /www/wwwroot -type f -newermt "2026-10-01" -not -path "*/cache/*" -not -path "*/runtime/*" | head -100

# 最近 7 天内被改动的 PHP 文件
find /www/wwwroot -name "*.php" -mtime -7 -not -path "*/cache/*" | head -50

# 常见后门特征扫描
grep -rlE "eval\(|assert\(|base64_decode\(|shell_exec\(|passthru\(|system\(|popen\(|proc_open\(" /www/wwwroot --include=*.php | head -50

4. 计划任务与启动项:持久化

webshell 只是入口,真正的麻烦是持久化。检查 crontab(crontab -l、/etc/cron.*、/var/spool/cron/)、systemd 服务与定时器、启动脚本、/etc/rc.local,以及 PHP 自身的 auto_prepend_file / auto_append_file 指向是否被改动过。

5. 凭据:攻击者拿到的最后一件事

拿到 RCE 之后,数据库配置文件(.env、config/database.php 这类)通常就在可读范围内。所以以下凭据一律视为已泄露,排查完成后必须全部轮换:

  • 数据库账号密码、后台管理员密码;
  • SSH 私钥与 authorized_keys;
  • 云厂商 / 对象存储 / 第三方 API 的 AccessKey;
  • 代码仓库的推送凭据。

三、恢复顺序不要搞反

发现 webshell 后,第一件事不是删文件。删掉但没查清入口,等于给对方留了后门。正确顺序是:

  1. 隔离:先从公网下线或用防火墙/WAF 阻断,保住现场(内存、日志、文件时间戳都会丢)。
  2. 取证:整站打包留存(至少是文件与日志),记录发现的时间点与文件清单。
  3. 查明入口:是这次漏洞,还是此前就存在的旧 webshell?两者经常同时存在。
  4. 清理或重建——见下。
  5. 轮换凭据:所有上一节列出的凭据,一次性换掉。
  6. 恢复上线并加强监控:异常请求告警、文件完整性校验、进程与计划任务基线对比。

四、什么时候应该直接重建,而不是清理

如果满足下面任意一条,建议放弃清理、直接重建:

  • 你无法确认攻击者在服务器上的活动范围与持续时间;
  • 机器上跑着不可信来源的第三方组件;
  • 有多个站点共用同一台机器或同一个 PHP-FPM 池;
  • 容器环境——用干净镜像重新构建,通常比在容器里清理更可靠;
  • 排查时间已经超过了你愿意承担的风险窗口。

清理 webshell 的难点从来不是删文件,而是证明已经没有第二个。重建能给你这个证明。

五、升级本身也别漏

  • 升级后重启 PHP 服务,并 reload 所有常驻进程——旧 worker 仍然持有漏洞代码;
  • 容器需要重新构建与重新部署,不是重启容器;
  • 确认线上实际跑的是修复版本:看 FPM 进程加载的配置与二进制版本,而不是看 php -v;
  • 升级完成后再做一次文件完整性对比,与干净副本逐文件比对哈希。

六、最后一句

这一次的排查清单,建议直接固化成一份可重复执行的脚本,存进运维仓库。安全事件的响应质量,取决于你第一次遇到时有多从容——而从容来自于事先就写好了流程。