🔥 CVE-2026-63030 深度独立研究:源码审计 · 二次发现 · 利用方案

🔥 高危漏洞深度独立研究 · CVSS ≥ 9.8

CVE-2026-63030 深度独立研究:源码审计 · 二次发现 · 利用方案

📊 3 来源🔍 源码审计🧪 PoC
CISA-KEVPoC-in-GitHubVulhub

🔍 源码独立审计

(未定位到源码) 源码进行独立审计(置信度 60%)。

🧬 根因独立理解

<p><strong>摘要:</strong>CVE-2026-63030 是 WordPress Core 中存在的一处解释冲突(Interpretation Conflict)漏洞,攻击者可在未认证的情况下利用 REST API 批量接口的路由混淆,将恶意请求透传到特权处理流程,进而执行 SQL 注入并可能实现远程代码执行(RCE)。该漏洞已被美国 CISA 列入已知被利用漏洞目录(KEV),且可链式利用 CVE-2026-60137 扩大攻击面。受影响版本包括 WordPress 6.9.0 至 6.9.4 以及 7.0.0 至 7.0.1。</p> <h2>📌 漏洞概述</h2> <p>CVE-2026-63030 被官方定性为 WordPress Core 的“解释冲突”漏洞,位于 REST 批量请求处理逻辑中。由于 WordPress Core 对子请求的验证与分发过程存在不匹配,攻击者可以构造特殊的 HTTP 请求,绕过权限校验,将未授权的操作映射到高权限的处理函数上,最终造成 SQL 注入与远程代码执行。</p> <p>该漏洞的 CVSS 评分尚未由官方公开,但鉴于其影响范围广、利用无需认证,且已被 CISA KEV 收录,其严重性评级应为“高”至“严重”。CISA 在 KEV 中明确指出,此漏洞可与 CVE-2026-60137 链式利用,并要求联邦机构按照 BOD 26-04 指令优先修补。</p> <p><strong>受影响版本:</strong></p> <ul> <li>&lt;= 6.8.5:不受影响</li> <li>6.9.0 – 6.9.4:受影响</li> <li>7.0.0 – 7.0.1:受影响</li> </ul> <p><strong>漏洞类型:</strong>解释冲突 / 权限校验绕过 / SQL 注入</p> <h2>🔬 漏洞根因分析</h2> <p>漏洞的核心根因在于 WordPress REST API 的批量端点(<code>/batch/v1</code>)在分发子请求时,错误地依赖两个并行数组的索引对齐来匹配“处理器”与“校验结果”。该端点本身被设计为未认证可访问,目的是让客户端在一个请求中并发多个子请求,每个子请求依然需要经过独立的权限检查和请求校验。然而,<code>serve_batch_request_v1()</code> 函数在处理子请求时,分别构建了 <code>$matches</code>(每个子请求匹配到的处理器)和 <code>$validation</code>(每个子请求的校验结果)这两个数组,并在后续调度阶段以相同的数字偏移量索引两个数组。</p> <p>当某个子请求的路径无法通过 <code>wp_parse_url()</code> 等解析函数时(例如,包含特殊字符或畸形路径),它会被追加到 <code>$validation</code> 数组中,却不会被追加到 <code>$matches</code> 数组中。这样一来,两个数组的长度不再一致,后续按偏移量进行调度时,一个子请求可能拿到另一个子请求的处理器(handler),造成“路由混淆”。攻击者可以精心构造两个子请求:一个恶意子请求的路径触发解析失败,在 <code>$validation</code> 中占位;另一个子请求虽然是高权限操作(比如创建文章或执行插件操作),但其路径被校验为普通请求,然后在调度时因为数组错位,却被分配了恶意子请求的处理器,或者反之——将本应被拒绝的请求交由不受限处理器执行。</p> <p>根据公开的 PoC(wp2shell-poc),利用该漏洞需要嵌套两次这种原语。第一次嵌套是将一个 <code>POST /wp/v2/posts</code> 请求(其 body 携带 <code>requests</code> 字段)伪装成批量请求的子请求,由于它在校验阶段被视为“文章创建请求”而被允许,但实际调度时落到了批量处理器 <code>serve_batch_request_v1()</code> 本身。批量处理器会继续展开该子请求中的 <code>requests</code> 列表,而这些内嵌的请求不再重新进行权限校验。第二次嵌套则利用同样的数组错位,将原本只允许普通权限的子请求提升为管理员级别的操作,或者直接引入包含 SQL 注入的字段,最终实现数据库读取和任意 SQL 语句执行。</p> <p>PoC 中 <code>check</code> 命令用于验证 SQL 注入路径的存在,<code>read</code> 命令演示了通过注入读取数据库内容,<code>shell</code> 命令则借助 SQLi-to-admin

🛤️ 漏洞触发链路

🧪 PoC 复现

从 GitHub 公开仓库抓取的实际 PoC 代码(仓库)。

📋 代码元数据语言md来源Icex0/wp2shell-poc针对性⚠️ 疑似通用代码(未检测到 CVE 引用,仅供参考)依赖见代码注释/README用法详见代码注释中的使用说明

# wp2shell-poc

Independent proof-of-concept for the unauthenticated WordPress REST batch route-confusion
SQL injection associated with Searchlight Cyber's wp2shell advisory.

This repository is not Searchlight Cyber's official checker. `check` confirms the SQLi path,`read` demonstrates database read,
and `shell` opens a plugin-backed command shell either with
supplied administrator credentials or by first exercising the SQLi-to-admin bridge.

![wp2shell — the `shell` command exercising the pre-auth SQLi-to-admin bridge](docs/shell.svg)

**Detection / IoCs:** Elastic Security Labs and Eye Security published detection guidance and indicators for this chain. See the [Elastic write-up](https://www.elastic.co/security-labs/wp2shell-wordpress-rce-detection-elastic-defend) and the [Eye Security defenders guide](https://labs.eye.security/wp2shell-defenders-guide/).

## Affected versions

Searchlight Cyber's advisory lists these wp2shell RCE exposure ranges:

|
Version range |Status ||------------- |------ ||<= 6.8.5 |Not affected ||6.9.0 – 6.9.4 |Affected ||7.0.0 – 7.0.1 |Affected |## How it works

The REST batch endpoint (`/batch/v1`) is unauthenticated and runs several sub-requests in one
call,
relying on each sub-request being validated and permission-checked on its own.

`serve_batch_request_v1()` builds two parallel arrays — `$matches` (the matched handler per
sub-request) and `$validation` (the validation result per sub-request) — then indexes both by
the same offset when dispatching. A sub-request whose path fails `wp_parse_url()` is appended to
`$validation` but not to `$matches`,
so the arrays fall out of step and a sub-request is
dispatched under a **different** sub-request's handler. That is the route confusion.

The PoC nests the primitive twice:

1. A `POST /wp/v2/posts` request that carries a `requests` body is dispatched under the batch
   handler itself. Having been validated as a posts request,its `requests` list is never checked
   against the batch schema,
so its sub-requests may use `GET` — the method allow-list is
   bypassed.
2. Inside that inner batch,a `GET /wp/v2/posts/999999` item-route request carries posts collection
   query params such as `author_exclude`,`orderby`,and `per_page`. The `999999` ID does not need
   to exist;it is just an unlikely post ID used to match the item route,
whose schema does not
   validate those collection-only params. The desync then dispatches the same request under posts
   `get_items()`,where `author_exclude` maps to the `WP_Query` `author__not_in` query var,
which
   the vulnerable build interpolates into SQL as a string.

The result is a boolean- and time-based blind SQL injection reachable pre-authentication. This PoC
also includes the UNION fake-post primitive used by the SQLi-to-admin chain.

The RCE path implemented here is:

1. Use UNION fake `wp_posts` rows to render attacker-controlled content through a posts collection.
   The render bridge uses the `/wp/v2/posts/999999` item-route source — the same route the SQLi read
   uses to reach `get_items()`.
2. Use that render to make WordPress create real oEmbed cache posts.
3. Recover those real cache post IDs through the SQLi.
4. In one poisoned batch request,
recast those IDs as a customizer changeset,navigation item,and
   request hook shape.
5. Let the same request reach `POST /wp/v2/users`,creating a generated administrator.
6. Log in as that generated administrator and use plugin upload behavior to run a command.

Steps 1–5 are pre-authentication;
the command-execution step is authenticated admin plugin upload.

## Requirements

Python 3.8+ and the standard library. No third-party dependencies.

## Usage

Run it from the repository directory:

```
./wp2shell.py <command><url>
[options]
```

Or `pip install .` to get a `wp2shell` command on your `PATH`.

### check — non-destructive vulnerability check

Prints passive WordPress markers and public version hints first,then sends a benign batch marker
probe. A vulnerable batch implementation returns HTTP 207 with the route-confusion marker pattern
`parse_path_failed`,`block_cannot_read`,
and `rest_batch_not_allowed`.

The marker probe is based on the WordPress core fix. The malformed `///` request creates
`parse_path_failed`;a `/wp/v2/posts` request acts as a batch-allowed spacer;the
`/wp/v2/block-renderer/...` route is not batch-allowed but returns `block_cannot_read` if its
handler is reached anonymously;
`/batch/v1` gives `rest_batch_not_allowed`. On vulnerable builds
the parse error shifts the batch handler arrays out of step,so the spacer request is dispatched
under the block-renderer handler. Fixed builds keep the arrays aligned,so this exact all-three
pattern should not appear for the crafted probe.

By default,
`check` stops there and does not send an SQLi payload. Use `--confirm-sqli` when you
also want an active SQLi confirmation. The confirmation tries the UNION read primitive first and
falls back to paired timing probes if UNION reflection is unavailable.

The signals are independent: a version hint is only a hint,the marker pattern shows route
confusion,
and `--confirm-sqli` shows a payload reached the database. A WAF can block the payload,
so a failed confirmation doesn't prove the bug is absent.

```
./wp2shell.py check http://target
./wp2shell.py check targets.txt          # scan every URL in the file
```

### read — extract data through SQL injection

```
./wp2shell.py read http://target                      # server fingerprint
./wp2shell.py read http://target --preset users       # user logins and password hashes
./wp2shell.py read http://target --query "SELECT @@version"
```

By default extraction is `--technique auto`,
which tries the available methods in this order:

1. **union** — forges a fake `WP_Post` row via `UNION` and reads its title back from the REST
   response as `||HEX(value)||`. The payload uses the same `/wp/v2/posts/999999` source route with
   `orderby=none` and `per_page=500` so the fake row survives as a rendered post. One request per
   value.
2. **error** — `EXTRACTVALUE`/`UPDATEXML` leak ~15 bytes per request,
when the target reflects
   MySQL errors (e.g. `WP_DEBUG_DISPLAY` on).
3. **blind** — boolean binary search,~8 requests per character;reads the posts collection
   `X-WP-Total` header as the true/false signal and needs no reflected value.

Force one with `--technique union|error|blind`. These read paths do not write database rows.

### shell — command execution

With `--user` and `--password`,
`shell` logs in with supplied administrator credentials and uses
WordPress plugin upload behavior.

Without credentials,`shell` first runs the pre-auth SQLi-to-admin bridge,logs in as the generated
administrator,
then uploads the plugin shell.

```
./wp2shell.py shell http://target --user admin --password '<recovered>' --cmd id
./wp2shell.py shell http://target --user admin --password '<recovered>' -i   # interactive shell
./wp2shell.py shell http://target --cmd id                                   # pre-auth bridge
./wp2shell.py shell http://target -i                                         # pre-auth interactive
```

`shell` uploads a plugin webshell (locked behind a random path and a per-run token) and prints its
path. The uploaded webshell is removed automatically. When the pre-auth bridge creates an
administrator,
that generated account is removed automatically after the shell session finishes.

## Options

|Option              |Applies to |Description                                                           ||------------------- |---------- |-------------------------------------------------------------------- ||`--proxy URL`       |all        |Route traffic through an HTTP proxy (for example,
Burp).             ||`--timeout N`       |all        |Request timeout in seconds.                                          ||`--sleep N`         |check      |Delay used by the timing fallback for `--confirm-sqli`.              ||`--samples N`       |check      |Timing pairs used by the timing fallback for `--confirm-sqli`.       ||`--confirm-sqli`    |check      |
Also send an active SQLi confirmation payload.                       ||`--preset`          |read       |`fingerprint` or `users`.                                            ||`--technique`       |read       |`auto` (default),`union` (in-band,forges a fake post),`error` (in-band,needs visible DB errors),or `blind`. ||`--query`           |read       |
A scalar SQL expression to read.                                     ||`--prefix`          |read       |Database table prefix (default `wp_`).                               ||`--max-length N`    |read       |Maximum characters read per value (default 128).                     ||`--user` / `--password` |shell  |Optional admin credentials;omit both to use the pre-auth bridge.   ||
`--cmd`             |shell      |Command to run (omit when using `-i`).                              ||`-i` / `--interactive` |shell   |Open an interactive shell after deploying.                           |## Remediation

Update to WordPress 7.0.2,or 6.9.5 if the site is on the 6.9 branch. Until then,block both `/wp-json/batch/v1` and the `rest_route=/batch/v1` query parameter at
the edge,
or require authentication for the batch endpoint via the
`rest_pre_dispatch` filter.

## Legal

For authorized security testing only. Use it exclusively against systems you own or have explicit
written permission to test. No warranty is provided and no liability is accepted for misuse.

## References

- WordPress 7.0.2 release announcement — <https://wordpress.org/news/2026/07/wordpress-7-0-2-release/>
- Searchlight Cyber wp2shell advisory — <https://slcyber.io/research-center/wp2shell-pre-authentication-rce-in-wordpress-core/>- Hackify — wp2shell technical analysis — <https://hackify.nl/en/blog/wp2shell-wordpress-core-rce/>- sergiointel/wp2shell-poc SQLi-to-admin bridge — <https://github.com/sergiointel/wp2shell-poc>- Elastic Security Labs — wp2shell detection &
IoCs — <https://www.elastic.co/security-labs/wp2shell-wordpress-rce-detection-elastic-defend>- Eye Security — wp2shell defenders guide — <https://labs.eye.security/wp2shell-defenders-guide/>

⚔️ EXP 利用代码

截至分析时,Exploit-DB 未收录该 CVE 的公开利用代码。可利用上述 PoC 进行验证,或关注 Exploit-DB 更新。

🕵️ 检测指纹

当前规则库未收录针对该 CVE 的专用检测规则。建议:

  • 根据漏洞根因编写 Nuclei 检测模板
  • 在 WAF/IDS 中配置针对漏洞特征的规则
  • 关注漏洞指纹库更新

🤖 高危漏洞深度独立研究引擎生成 · 2026-08-04 12:01

[!] CONTACT_CHANNELS

如需商务合作、技术咨询或漏洞反馈,请通过以下离岸节点联系作者。

> PING_AUTHOR (@A1RedTeam)