PHP2Shell 修复 Skill(供 AI Agent 使用)
你(AI agent)的任务:在一台受影响的机器上,把 PHP 修到不受 PHP2Shell 攻击的状态。本 skill 给出完整决策流程。禁止跳过探测直接给方案。
0. 漏洞事实卡(先自己读懂)
- 两个洞同根:PHP 处理致命错误用
longjmp()直接跳出请求不留清理,半初始化/悬空内存状态被后续清理代码或下一个请求使用 - 无需登录,攻击流量走业务端口(80/443),应用层登录/WAF/维护模式全部拦不住(攻击发生在应用代码运行前,尤其 mod_php)
- 除 RCE 外还能读 worker 进程内存(其他请求的密码/会话令牌/API 密钥)
- 官方修复版本:8.2.35 / 8.3.36 / 8.4.27 / 8.5.12(2026-10-21 发布)
- 官方 minimal source backport:仅 7.4 / 8.0 / 8.1
- 7.3 及更早(含 5.x):官方零支持,但 sury.org 已把补丁 backport 到 5.6–8.1 全部分支(2026-10-21,Debian/Ubuntu 打包,patch 可抽取复用)
- CVSS v4.0 双 9.2;Cloudflare 在补丁发布前已观察到攻击尝试
- 官方明确:没有能完全替代升级的缓解措施
1. 探测(必做,输出一份现状清单)
# 1) web 层真实版本(最重要!CLI 版本可能和 web SAPI 不一致)
php -v # CLI
php-fpm -v 2>/dev/null || true # FPM(如存在)
# mod_php 场景:放一个 <?php echo PHP_VERSION; 的页面 curl 访问,确认 web 层版本
# 2) 部署架构:mod_php / php-fpm / php-cgi / FrankenPHP / LiteSpeed
httpd -M 2>/dev/null | grep -i php # Apache 模块
ps aux | grep -E 'php-fpm|php-cgi' | grep -v grep
nginx -T 2>/dev/null | grep -i 'fastcgi_pass|php'
# 3) 现有构建参数(源码编译场景复用)
php-config --configure-options 2>/dev/null
# 4) OS 与包管理器
cat /etc/os-release; which yum dnf apt apk 2>/dev/null
# 5) 暴露面(决定优先级)
# 从外网 curl -I http://目标IP/ 能通 → P0 紧急;仅内网/堡垒机可达 → P1
常见坑:php -v 显示 8.3 但网站实际跑的是另一个 PHP(多版本共存、Remi SCL、面板切换)。必须以 web SAPI 实际加载的版本为准。
2. 按版本分流(核心决策树)
PHP 版本?
├─ 8.2 / 8.3 / 8.4 / 8.5 → 官方补丁版本:8.2.35 / 8.3.36 / 8.4.27 / 8.5.12
│ → 按 references/system-matrix.md 对应系统一条命令升级,重启服务,完事
├─ 8.0 / 8.1 / 7.4 → 官方有 minimal source backport
│ → 优先找 distro/LTS 厂商包(Debian/Ubuntu sury、CloudLinux TuxCare 等)
│ → 没有包就源码编译:官方 backport 或 sury 同版本 patch,见 references/eol-patch-porting.md
├─ 5.6 / 7.0 / 7.1 / 7.2 / 7.3 → 官方零支持
│ → Debian/Ubuntu:sury 源直接 apt 升级(sury 已 backport 到 5.6)
│ → 其他系统:从 sury Debian 源码包抽 patch 打到官方原始源码编译
│ (已验证:5.6 的 patch 在 php.net museum 原始源码上零 reject 干净应用)
│ 完整方法见 references/eol-patch-porting.md,CentOS 6 现成实现见本包 centos6-php56/
└─ < 5.6 → patch 都没有了,唯一正解是升级;过渡期用第 3 节缓解 + 隔离
Remi 仓库注意:Remi(RHEL 系常用第三方源)在发布当日明确没有同步更新,且其 EOL 分支早已停维护。RHEL 系跑 EOL PHP 的,直接走"抽 sury patch + 源码编译"路线。
3. 修不动时的临时缓解(不完整,只是争取时间)
按攻击面逐条堵,用 php_admin_value(FPM pool 或 Apache 配置)强制下发防应用覆盖:
; CVE-2026-109618:让攻击者无法在"半初始化时刻"触发内存耗尽
memory_limit = -1
post_max_size = 8M ; 无上传业务 8M,有上传 32M
; CVE-2026-109619:切断已验证的 session 上传进度触发路径
session.upload_progress.enabled = 0
改完必须重启所有 PHP worker(php-fpm 全部 pool / httpd)。
更狠但有效:下线、IP 白名单、套 Cloudflare(免费 WAF 规则已覆盖已知向量)。
改配置 ≠ 修复,能编译就编译。
4. 通用源码编译流程(任何 EOL 版本,任何 Linux)
- 拿官方原始源码:
https://museum.php.net/php5/php-5.6.40.tar.gz(5.x);7.x/8.x 用https://www.php.net/releases/对应归档 - 拿补丁:见 references/eol-patch-porting.md(sury 包抽取法 + 移植法)
patch -p1 --dry-run验证干净应用(有 reject 就按移植法处理,不要硬打)./configure(复用php-config --configure-options,去掉旧 prefix/apxs 路径按本机调整)→make -j$(nproc)- 不要
make install。备份后只替换两个东西:web SAPI 二进制(mod_php 的libs/libphp5.so或 FPM 的sapi/fpm/php-fpm)+ CLI(sapi/cli/php) - 重启 web 服务,验证(第 5 节),留好回滚备份
- 老 OS 先修源:CentOS 6 →
mirrors.aliyun.com/centos-vault/6.10;CentOS 7 →centos-vault/7.9.2009;EPEL →mirrors.aliyun.com/epel-archive/
5. 验证(三关全过才算修完)
# 关1:版本/构建日期变了
php -v # Build date 应为修复日之后
# 关2:补丁代码真的编进去了(补丁新增导出符号)
nm <web层二进制: libphp5.so 或 php-fpm> | grep zend_mm_safe_error_ex # 有输出=OK
# 关3:服务真的在跑新二进制
systemctl restart php-fpm httpd 2>/dev/null; ps aux | grep php # 启动时间=刚才
修完做入侵回查(攻击可能早于修复):web 根目录新文件/webshell、异常 cron、web 用户发起的出站连接、php-fpm/httpd spawn 出的 shell 进程,日志回溯至少到 2026-06。
6. 硬规则(agent 必须遵守)
- 动手前先输出探测结果 + 选定路线,让用户确认再改(替换二进制是高危操作)
- 任何替换前必须备份原二进制,保留一键回滚路径
- web SAPI 版本 > CLI 版本,以 web 层为准
- 补丁 dry-run 不干净 → 走移植法,不许
patch --force硬上 - 修完必须过第 5 节三关验证,缺一不可
- 明确告知用户:EOL 版本打补丁只是止血,整套系统的迁移计划仍要排
7. 参考资料
- 官方公告:php.net security releases(GHSA-w8hw-w9fx-j79w / GHSA-6wmf-4rv5-p3rp)
- PHP Foundation 说明:thephp.foundation/blog/2026/10/21/todays-php-security-release-and-how-were-strengthening-php-security/
- EOL 分支 backport 来源:packages.sury.org/php/(Debian 源码包内含 patch)
- 系统对照速查 →
references/system-matrix.md - EOL 补丁抽取与移植方法 →
references/eol-patch-porting.md - 已验证实战案例(CentOS 6.5 + PHP 5.6)→ 本包
../centos6-php56/