【漏洞预警】WordPresswp2shell紧急漏洞预警:CVE-2026-63030/CVE-2026-60137未授权RCE链

admin 2026-07-22 08:05:08 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: WordPress7.0.0-7.0.1及6.9.0-6.9.4版本存在严重RCE漏洞链wp2shell,由CVE-2026-63030(RESTAPI路由混淆,CVSS9.8)与CVE-2026-60137(SQL注入,CVSS5.9)串联组成,无需认证即可在默认配置下实现远程代码执行。已有野外利用报告和公开PoC。建议立即升级至7.0.2/6.9.5/6.8.6等修复版本,并检查日志和数据库IOC确认是否已被利用。 综合评分: 87 文章分类: 漏洞预警,漏洞分析,应急响应,渗透测试,红队


cover_image

【漏洞预警】WordPress wp2shell 紧急漏洞预警:CVE-2026-63030 / CVE-2026-60137 未授权 RCE 链

猎户攻防实验室

2026年7月19日 09:32 北京

在小说阅读器读本章

去阅读

2026 年 7 月 17 日,WordPress 发布 7.0.2 / 6.9.5 / 6.8.6 与 7.1 beta 2 安全版本,修复由两个核心漏洞串联而成的 wp2shell 攻击链:

  • • CVE-2026-63030 — REST API batch/v1 批处理路由混淆,CNA CVSS 9.8 Critical
  • • CVE-2026-60137 — WP_Query 的 author__not_in SQL 注入,CNA CVSS 5.9 Medium

两者串联后,在默认配置、无需认证、无需任何插件的情况下,可对开箱即用的 WordPress 实现远程代码执行。Patchstack 已将 CVE-2026-63030 标记为”Known to be exploited”(2026-07-17 晚 7 点 ET 前已有野外利用报告),公开 PoC 已在 GitHub 流通。

一、影响版本

必须按分支判断,不要用”版本号 ≥ 某值即安全”的跨分支比较(7.0.0 数值上大于 6.9.5,但仍受影响)。

| WordPress 版本 | CVE-2026-60137 | CVE-2026-63030 | 风险 | | — | — | — | — | | < 6.8 | — | — | 不受影响 | | 6.8.0 – 6.8.5 | ✅ | — | 仅 SQLi | | 6.9.0 – 6.9.4 | ✅ | ✅ | 完整 wp2shell RCE 链 | | 7.0.0 – 7.0.1 | ✅ | ✅ | 完整 wp2shell RCE 链 | | 7.1 beta 1 | ✅ | ✅ | 必须更新 | | 6.8.6 / 6.9.5 / 7.0.2 / 7.1 beta 2 | — | — | 已修复 |

二、攻击链与实测证据

入口:WordPress REST API 支持两种等价访问形式,防护必须同时覆盖

POST /wp-json/batch/v1 &nbsp; &nbsp; &nbsp; &nbsp;# path 形式
POST /?rest_route=/batch/v1 &nbsp; # query 形式 ← PoC 实测默认走这个

攻击链

  1. 1. 向 batch/v1 发送构造的批处理请求,触发 REST API 子请求匹配与调度之间的路由混淆;
  2. 2. 被错误调度的子请求把请求参数 author_exclude 映射到 WP_Query 的 author__not_in,因未做完整整数化处理 → SQL 注入;
  3. 3. 通过 UNION 假文章原语拖取 wp_users 表(实测:3 个请求拿到管理员 bcrypt 哈希 $wp$2y$10$...);
  4. 4. 利用 SQLi 在 wp_posts 伪造 customizer changeset / nav menu item → 自动创建名为 wp2_<16hex> 的管理员账号;
  5. 5. 用该管理员身份上传插件 webshell → RCE。

实测(隔离 Docker 环境,WordPress 7.0.1 默认配置):

完整链路(check → read → shell)在受影响版本上稳定复现;在 7.0.2 上 UNION 原语即不可用,桥接在第一步失败。

三、紧急排查

第 1 步:版本确认

wp core version
# 或无 WP-CLI 时
grep&nbsp;'\$wp_version[[:space:]]*='&nbsp;/var/www/html/wp-includes/version.php

判读:

| 实际版本 | 处置 | | — | — | | 6.9.0 – 6.9.47.0.0 – 7.0.1 / 7.1 beta 1 | 完整链路暴露,按 P0 立即处置 | | 6.8.0 – 6.8.5 | 仅 SQLi,检查插件/主题是否暴露该参数,升级到 6.8.6 | | 6.8.66.9.5 / 7.0.2 / 7.1 beta 2 | 已修复 |

⚠️ 不要用”版本 ≥ 6.9.5″判断安全。7.0.0 数值上大于 6.9.5 但仍受影响。

第 2 步:检查 batch 入口是否可达

空 batch 请求探测(不含任何 payload,只判断路由是否暴露):

for&nbsp;url&nbsp;in&nbsp;\
&nbsp;&nbsp;'https://YOUR_SITE/wp-json/batch/v1'&nbsp;\
&nbsp;&nbsp;'https://YOUR_SITE/?rest_route=/batch/v1'
do
&nbsp; curl -ksS --connect-timeout 10 -o /dev/null \
&nbsp; &nbsp; -w&nbsp;"$url&nbsp;-> HTTP %{http_code}\n"&nbsp;\
&nbsp; &nbsp; -H&nbsp;'Content-Type: application/json'&nbsp;--data&nbsp;'{"requests":[]}'&nbsp;"$url"
done

判读:

| path 形式 | query 形式 | 含义 | | — | — | — | | 200 | 207 | 受影响版本的典型表现 (实测:受影响的 WP 7.0.1 上 path 形式 200、query 形式 207) | | 200207 / 明确 REST 参数错误 | 同左 | 入口可达,需结合版本判断风险 | | 401403 | 同左 | 已被认证策略或安全设备阻断(缓解已生效) | | 404 | 同左 | 路由不可达,或被 WAF/重写规则隐藏 —— 不能单独据此判定安全 |

⚠️ 不要用 curl -I(HEAD 请求)测 batch/v1。实测 HEAD 会被 pretty-permalink 重写规则返回 301/404/405,即使 POST 实际可达。

第 3 步:访问日志找入口请求

⚠️ 必须同时匹配 path 形式和 query 形式,只匹配 path 形式会漏报(PoC 默认走 query 形式):

# 覆盖两种形式的入口请求
zgrep -hEi&nbsp;'"POST [^"]*(/wp-json/batch/v1/?|[?&]rest_route=(%2f|/)?batch(%2f|/)v1)'&nbsp;\
&nbsp; /var/log/nginx/access.log* /var/log/apache2/access.log* 2>/dev/null

# PoC 默认 User-Agent 是字面值 "wp2shell",可作为附加筛选
zgrep -hE&nbsp;'"wp2shell"$'&nbsp;/var/log/nginx/access.log* /var/log/apache2/access.log* 2>/dev/null

命中后进一步提取:源 IP、User-Agent、状态码、请求大小、同源频率、CDN/源站日志是否能对应。

单次 batch POST 也可能是正常功能调用,不能仅凭路径判定入侵。但受影响版本上出现来源不明、频率异常或体积超大的 batch POST,应立即升级为高优先级调查。

第 4 步:数据库 IOC 检查(实测高可靠)

⚠️ 关于 PoC 清理行为(实测结论)

  • • PoC 预认证桥接建的临时管理员和 webshell 插件正常退出时会清理(实测从干净基线跑一次后,wp_users 和 plugins/ 都恢复原状)
  • • 但 PoC 客户端(urllib)在网络不稳时会出现 IncompleteRead 异常中断,中断时不会执行清理逻辑,会留下 wp2_<16hex> 管理员账号和 wp2shell_<8hex> webshell 目录
  • • PoC 完全不清理 wp_posts 伪造记录,每次跑都新增 2 条 —— 这是最可靠的入侵 IOC,比 wp_users 检查更稳

下面两条 SQL 都建议执行,互为补充:

先拿实际表前缀:

wp db prefix &nbsp; &nbsp;# 通常返回 wp_,但很多站点做过硬化
-- 实测 IOC 1:PoC 桥接创建的临时管理员(残留)
SELECT&nbsp;ID, user_login, user_email, user_registered
FROM&nbsp;<prefix>users
WHERE&nbsp;user_login&nbsp;LIKE&nbsp;'wp2\_%'
&nbsp; &nbsp;OR&nbsp;user_registered&nbsp;>&nbsp;'2026-07-10'
ORDER&nbsp;BY&nbsp;user_registered&nbsp;DESC;

-- 实测 IOC 2:PoC 伪造的 wp_posts
-- 特征:post_type IN ('customize_changeset','nav_menu_item','request')
-- &nbsp; &nbsp; &nbsp;且 post_date 硬编码为 '2020-01-01 00:00:00'
SELECT&nbsp;ID, post_type, post_status, post_date,&nbsp;LEFT(post_title,&nbsp;50)
FROM&nbsp;<prefix>posts
WHERE&nbsp;(post_type&nbsp;IN&nbsp;('customize_changeset','nav_menu_item','request')
&nbsp; &nbsp; &nbsp; &nbsp;AND&nbsp;post_date&nbsp;=&nbsp;'2020-01-01 00:00:00')
&nbsp; &nbsp;OR&nbsp;post_title&nbsp;LIKE&nbsp;'wp2\_%';

判读:任一查询有结果 → 基本确认已被 PoC 利用

补充检查管理员角色(用于发现已存在账号被提权):

SELECT&nbsp;u.ID, u.user_login, u.user_email, u.user_registered
FROM&nbsp;<prefix>users u
JOIN&nbsp;<prefix>usermeta um&nbsp;ON&nbsp;um.user_id&nbsp;=&nbsp;u.ID
WHERE&nbsp;um.meta_key&nbsp;=&nbsp;'<prefix>capabilities'
&nbsp;&nbsp;AND&nbsp;um.meta_value&nbsp;LIKE&nbsp;'%administrator%'
ORDER&nbsp;BY&nbsp;u.user_registered&nbsp;DESC;

PHP/Apache 错误日志取证:UNION 注入触发时,WordPress 的 wpdb::print_error() 会把完整 SQL 写入 PHP error log。具体位置取决于部署方式:

  • • Apache + mod_php/var/log/apache2/error.log 或 /var/log/httpd/error_log
  • • Nginx + PHP-FPM/var/log/php-fpm.log 或 /var/log/php/error.log
  • • Docker 容器:PHP error_log 通常指向 stderr,通过 docker logs <container> 查看
  • • wp-content/debug.log仅当 wp-config.php 同时设置 define('WP_DEBUG', true) 和 define('WP_DEBUG_LOG', true) 时才会生成(默认 WordPress 镜像不会自动开启,所以这个文件大概率不存在,不要直接 grep 它)
# Apache 部署
grep -hE&nbsp;'UNION ALL SELECT|post_author NOT IN'&nbsp;/var/log/apache2/error.log* 2>/dev/null

# Nginx + PHP-FPM 部署
grep -hE&nbsp;'UNION ALL SELECT|post_author NOT IN'&nbsp;/var/log/php*/error*.log&nbsp;2>/dev/null

# Docker 部署
docker logs <wordpress-container> 2>&1 | grep -E&nbsp;'UNION ALL SELECT|post_author NOT IN'

# 仅当显式开启 WP_DEBUG_LOG=true 时才存在
grep -hE&nbsp;'UNION ALL SELECT|post_author NOT IN'&nbsp;/var/www/html/wp-content/debug.log* 2>/dev/null

命中即强烈表明已遭 PoC 利用 —— payload 中可见伪造的 customize_changeset / nav_menu_item / request 等 post_type 字符串。

第 5 步:文件 IOC 检查

实测 PoC webshell 落在 wp-content/plugins/ 目录(通过管理员插件上传功能写入,另外会自动清理,不作为唯一排查证据)。下面第 1 条是 wp2shell 专属 IOC,第 2-4 条是通用 webshell 排查:

# 1. wp2shell 专属 IOC:实测 webshell 路径模式
# &nbsp; &nbsp;PoC 通过插件上传能力写到 plugins/wp2shell_<8hex>/wp2shell_<8hex>.php
find /var/www/html/wp-content/plugins -type&nbsp;d -name&nbsp;'wp2shell_*'&nbsp;2>/dev/null
find /var/www/html/wp-content/plugins -type&nbsp;f -path&nbsp;'*/wp2shell_*/*.php'&nbsp;2>/dev/null

# 2. 通用排查:事件窗口内新增/修改的可疑 PHP 文件(含危险函数)
# &nbsp; &nbsp;排除 wp-config.php / wp-config-docker.php(容器构建产物,含 base64 是 wp_salt 用,属误报)
find /var/www/html -type&nbsp;f -name&nbsp;'*.php'&nbsp;-newermt&nbsp;'2026-07-10'&nbsp;\
&nbsp; -not -name&nbsp;'wp-config.php'&nbsp;-not -name&nbsp;'wp-config-docker.php'&nbsp;\
&nbsp; -print0 2>/dev/null \
&nbsp; | xargs -0 -r grep -lE&nbsp;'eval[[:space:]]*\(|base64_decode[[:space:]]*\(|shell_exec[[:space:]]*\('&nbsp;2>/dev/null

# 3. 通用排查:uploads 目录原则上不应有可执行 PHP
# &nbsp; &nbsp;(wp2shell 实测不会写这里,但其它攻击向量常滥用 uploads)
find /var/www/html/wp-content/uploads -type&nbsp;f \
&nbsp; \( -iname&nbsp;'*.php'&nbsp;-o -iname&nbsp;'*.phtml'&nbsp;-o -iname&nbsp;'*.phar'&nbsp;\) 2>/dev/null

# 4. 核心 checksum 校验
wp core verify-checksums
wp plugin verify-checksums --all

判读

  • • 命中第 1 条 find wp2shell_* → 几乎确定是 PoC webshell(PoC 正常退出会清理,异常退出时残留)
  • • 命中第 2 条 → 通用 webshell 嫌疑,需结合文件来源、修改时间、checksum 综合判断
  • • 命中第 3 条 → 非本次 PoC 特征,但应立即调查(其它攻击向量)
  • • wp plugin verify-checksums 报 Couldn't fetch response ... 404 → 该插件不在 WordPress.org checksum 库,这本身是 IOC(实测:PoC 上传的 wp2shell_<8hex> 会触发此警告)
  • • wp core verify-checksums 报 File should not exist: wp-config-docker.php → Docker 镜像特例,非入侵痕迹

四、修复

4.1 首选方案:升级到对应分支安全版本

升级前先备份(数据库 + wp-content + wp-config.php):

# 默认升级到最新稳定版(当前 7.0.2)
wp core update
wp core verify-checksums
wp core version &nbsp; &nbsp;# 确认精确版本,不是"大于某值"

# 需要保留当前分支时显式指定(按实际分支选其一,不要全跑)
wp core update --version=7.0.2 &nbsp; &nbsp;# 7.x 分支
wp core update --version=6.9.5 &nbsp; &nbsp;# 6.9 分支
wp core update --version=6.8.6 &nbsp; &nbsp;# 6.8 分支

4.2 Docker 部署升级陷阱

只跑 docker pull 不够 —— Compose 不会自动用新镜像,必须 --force-recreate

# 1. 先改 compose 文件里的 image: 标签为安全版本
# &nbsp; &nbsp;image: wordpress:7.0.2-apache

# 2. 重新拉取 + 强制重建
docker compose pull
docker compose up -d --force-recreate

# 3. 验证容器内实际 WP 版本(不能只看镜像 tag)
docker compose&nbsp;exec&nbsp;wordpress php -r \
&nbsp;&nbsp;'include "/var/www/html/wp-includes/version.php"; echo $wp_version, PHP_EOL;'

⚠️ 升级前确认数据库、wp-contentuploads 都在持久化卷中,且有可恢复备份。

⚠️ 截至 2026-07-19,Docker Hub 上 wordpress:7.0.2 尚未发布wordpress:7.0.1-php8.2-apache 有 arm64 变体)。Docker 部署的站点建议改用容器内 wp core update 升级,等官方镜像或自行构建。

4.3 发行版包管理器部署(apt)

如果 WordPress 由 Debian/Ubuntu 包管理,应优先遵循发行版安全公告:

apt update && apt install --only-upgrade wordpress

发行版可能用回补补丁而非升级版本号,不能只看版本字符串判断是否修复,需对照发行版 changelog。

4.4 升级后验证

升级完成不等于安全,必须复测

# 1. 版本精确落在安全分支
wp core version &nbsp; &nbsp;# 应输出 6.8.6 / 6.9.5 / 7.0.2

# 2. checksum 通过
wp core verify-checksums &nbsp; &nbsp;# 应输出 "Success: WordPress installation verifies against official checksums."

# 3. 用第 2 步的探测确认 batch 入口行为符合预期(已升级版本上 POST 仍可达但 SQLi 失败)

五、无法立即升级时的临时缓解

临时措施必须同时覆盖两种入口:

/wp-json/batch/v1
/?rest_route=/batch/v1

5.1 MU 插件兜底(最稳,所有部署方式通用)

wp-content/mu-plugins/block-wp2shell.php

<?php
/**
&nbsp;* wp2shell emergency mitigation.
&nbsp;* Remove after upgrading to 6.8.6 / 6.9.5 / 7.0.2.
&nbsp;*
&nbsp;* 实测:rest_pre_dispatch 在 REST 路由规范化之后触发,
&nbsp;* &nbsp; &nbsp; &nbsp; 因此同时覆盖 path 和 query 两种入口。
&nbsp;*/
add_filter('rest_pre_dispatch',&nbsp;static&nbsp;function ($result,&nbsp;$server,&nbsp;$request) {
&nbsp; &nbsp;&nbsp;if&nbsp;('/batch/v1'&nbsp;===&nbsp;untrailingslashit($request->get_route())) {
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;new&nbsp;WP_Error('wp2shell_blocked',
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'REST batch endpoint temporarily disabled.',&nbsp;array('status'&nbsp;=>&nbsp;403));
&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;return&nbsp;$result;
},&nbsp;10,&nbsp;3);

部署后从站点外部复测两个入口都应返回 403

for url in \
&nbsp; 'http://localhost:8083/wp-json/batch/v1' \
&nbsp; 'http://localhost:8083/?rest_route=/batch/v1'
do
&nbsp; curl -ksS -o /dev/null -w "$url -> HTTP %{http_code}\n" \
&nbsp; &nbsp; -H 'Content-Type: application/json' --data '{"requests":[]}' "$url"
done

5.2 Nginx 边缘层加固(与 MU 插件叠加,推荐)

# Pretty permalink 形式
location&nbsp;~* ^/(?:index\.php/)?wp-json/batch/v1/?$&nbsp;{
&nbsp; &nbsp;&nbsp;return&nbsp;403;
}

# Query 形式(PoC 实测真实流量,必须保留这条)
if&nbsp;($args&nbsp;~* "(^|&)rest_route=(%2f|/)batch(%2f|/)v1/?(&|$)")&nbsp;{
&nbsp; &nbsp;&nbsp;return&nbsp;403;
}

⚠️ 不要把阻断 /wp-json/wp/v2/users 当作修复。漏洞利用的子请求由 WordPress 内部 REST 服务器调度,不会作为新的外部 HTTP 请求再次经过 Nginx,所以这条规则对 wp2shell 无效。

5.3 Apache .htaccess 加固(适用 Apache + mod_rewrite)

⚠️ 实测注意事项

  • • .htaccess 仅在 Apache 主配置对 /var/www/html 设了 AllowOverride All(或 FileInfo)时才生效。WordPress 官方 Docker 镜像在 docker-php.conf 里启用了 AllowOverride All,但部分定制镜像可能没启用 —— 不确定时优先用 MU 插件方案。
  • • path 形式的 RewriteRule 在 .htaccess 里容易被 WordPress 标准 RewriteRule . /index.php [L] 抢先匹配而失效(实测命中此问题)。建议把 wp2shell 拦截规则放在 # BEGIN WordPress 块之前,或干脆只依赖 query 形式拦截 + MU 插件。
# 放在 # BEGIN WordPress 之前,确保优先匹配
RewriteEngine&nbsp;On

# Query 形式(PoC 实测真实流量,实测可拦)
RewriteCond&nbsp;%{QUERY_STRING}&nbsp;(^|&)rest_route=(%2F|/)batch(%2F|/)v1/?(&|$)&nbsp;[NC]
RewriteRule&nbsp;^ -&nbsp;[F,L]

# Path 形式(注意:必须放在 WP 标准 index.php 重写之前才生效)
RewriteCond&nbsp;%{REQUEST_URI}&nbsp;^/(?:index\.php/)?wp-json/batch/v1/?$&nbsp;[NC]
RewriteRule&nbsp;^ -&nbsp;[F,L]

5.4 三层防御实测对比

| 测试场景 | Nginx | MU 插件 | .htaccess | PoC check 结果 | | — | — | — | — | — | | 三层全启用 | ✅ | ✅ | ✅ | HTTP 403,被 Nginx 拦 | | 仅禁用 Nginx(保留反代) | ❌ | ✅ | ✅ | HTTP 403,被 MU 插件拦 | | 禁用 Nginx + MU 插件 | ❌ | ❌ | ✅(query 形式) | HTTP 403,被 .htaccess 拦 query 形式 |

实测细节

  • • Nginx 和 MU 插件两层对 path 和 query 两种形式都完全有效
  • • .htaccess 层实测对 query 形式有效,对 path 形式(/wp-json/batch/v1容易被 WP 标准重写规则抢先而失效,所以建议把 .htaccess 作为第三道兜底,不要单独依赖
  • • 生产建议:Nginx(边缘)+ MU 插件(应用)两层叠加即可,无需依赖 .htaccess

结论:Nginx 和 MU 插件任一层独立即可阻断整条攻击链;.htaccess 不可靠,仅作兜底。

六、发现失陷后的处置

如果第 4、5 步发现 IOC,不能只升级 WordPress

  1. 1. 隔离站点 + 取证:切换维护页或断公网,保留磁盘、容器、数据库、日志快照;
  2. 2. 从可信镜像/干净安装包重建核心、插件、主题,不要只删可疑文件(无法保证后门清理干净);
  3. 3. 重置所有管理员密码,撤销可疑的 Application Password;
  4. 4. 更新 wp-config.php 的 Authentication Keys and Salts(使所有现有登录会话失效):
   wp config shuffle-salts &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# 注意是 shuffle-salts(带 s),不是 shuffle-salt
   # Docker 部署:因 wp-config.php 用 getenv_docker() 包装,还需改容器的 SALT 环境变量
  1. 5. 轮换关联凭据:数据库、SMTP、CDN、对象存储、第三方 API key;
  2. 6. 检查持久化:计划任务、MU 插件、额外主题/插件、系统 cron、Web 服务账号的 SSH 密钥;
  3. 7. 评估通报义务:根据日志确认最早攻击时间,评估数据库/用户数据是否泄露,按本地合规要求履行通报。

参考

  • • WordPress 7.0.2 Security Release(官方公告) https://wordpress.org/news/2026/07/wordpress-7-0-2-release/
  • • CVE-2026-63030(CVE.org,CVSS 9.8) / CVE-2026-60137(CVSS 5.9) https://www.cve.org/CVERecord?id=CVE-2026-60137
  • • Searchlight Cyber — wp2shell 原始研究 https://slcyber.io/research-center/wp2shell-pre-authentication-rce-in-wordpress-core/
  • • Rapid7 ETR — CVE-2026-63030 https://www.rapid7.com/blog/post/etr-cve-2026-63030-wp2shell-a-critical-remote-code-execution-vulnerability-in-wordpress-core/

#


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:猎户攻防实验室 《【漏洞预警】WordPress wp2shell 紧急漏洞预警:CVE-2026-63030 / CVE-2026-60137 未授权 RCE 链》

评论:0   参与:  0