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

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

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

订阅源联系隐私© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
wp2shell-lab — 非破坏性检测器 + Docker 实验室,用于 wp2shell(CVE-2026-63030 REST /batch/v1 路由混淆 + CVE-2026-60137 author__not_in SQLi)在 WordPress 核心 6.9.0-6.9.4 / 7.0.0-7.0.1 中 | Kitploit
工具/GitHubGitHub/dinosn/wp2shell-lab
漏洞分析漏洞利用Web应用程序漏洞利用渗透测试学习与教育实验室与实践
GitHubdinosn/wp2shell-lab

wp2shell-lab

非破坏性检测器 + Docker 实验室,用于 wp2shell(CVE-2026-63030 REST /batch/v1 路由混淆 + CVE-2026-60137 author__not_in SQLi)在 WordPress 核心 6.9.0-6.9.4 / 7.0.0-7.0.1 中

查看仓库
5417443个月前Kitploit 审核通过

最受欢迎

查看全部 →

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

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

wp2shell 实验环境与检测器 + 预认证 RCE PoC

一个自包含的实验环境、非破坏性检测器,以及针对 wp2shell 的完整预认证 RCE 概念验证——WordPress 核心中的预认证漏洞链:

CVE组件类别CVSS
CVE-2026-60137WP_Query::author__not_inSQL 注入(CWE-89)9.1
CVE-2026-63030REST /batch/v1 路由混淆解释冲突(CWE-436)→ 链式利用至 RCE7.5

受影响版本: WordPress 核心 6.9.0–6.9.4 和 7.0.0–7.0.1(仅 SQLi 注入点也影响 6.8.0–6.8.5)。已在 6.8.6 / 6.9.5 / 7.0.2 中修复。 由 Adam Kues(Assetnote / Searchlight Cyber)报告;SQLi 同时归功于 TF1T、dtro、haongo。默认配置 RCE 链(oEmbed → changeset → 重入)由 Mustafa Can İPEKÇİ(nukedx)完成。

请先更新。 WordPress 已为此发布强制自动更新。本仓库的存在是为了帮助你 验证自己的资产是否已打补丁,并理解该漏洞——而非攻击任何人。参见 SECURITY.md。


它究竟是什么

恒真原语是一个无需认证、无需插件、原生核心的 SQL 注入,可提供 完整的数据库读取(管理员密码哈希、wp_options/wp_users 中的一切内容)。仅此一项就足以 获得 9.1 的评分并需要立即打补丁。

RCE 是真实的,且在默认配置的 WordPress 上有效——不需要 FILE 权限、不需要持久化 对象缓存、不需要插件、不需要任何错误配置。该链利用只读 SQLi 作为 行伪造原语(UNION ALL SELECT 注入伪造的 wp_posts 行),然后利用 WordPress 自身的内容渲染管线,通过 oEmbed 缓存将这些伪造行转化为真实的数据库写入。 由此,changeset 提权和可重入的 parse_request 在管理员上下文中运行,创建一个新的管理员账户——全部来自单个未认证的 HTTP 请求。

完整链条(无凭据,单一入口点 POST /?rest_route=/batch/v1)

1. Route confusion    — double-nested batch desyncs $matches/$validation so a GET
                        /wp/v2/widgets runs under posts::get_items() (public), reaching
                        WP_Query's author__not_in with attacker-controlled input.

2. Row forgery        — author__not_in is string-concatenated into SQL;
                        "1) AND 1=0 UNION ALL SELECT <23 cols> -- -" injects fake
                        WP_Post rows. per_page=-1 bypasses split_the_query (WP_Query
                        treats -1 as "no limit" → empty $limits → split=false →
                        full SELECT wp_posts.* → UNION columns match).

3. oEmbed write       — forged posts carry [embed]<self-url>[/embed]; rendering via
                        context=view makes WordPress cache real oembed_cache posts in
                        the DB (turns read-only SQLi into writes with predictable IDs).

4. Elevation+re-entry — a forged customize_changeset (user_id = real admin) plus a
                        forged post_type=request row with parent loops drives an
                        in-process re-entrant parse_request in admin context.

5. Admin creation     — POST /wp/v2/users in the same batch passes
                        current_user_can('create_users') → new administrator.

6. RCE                — login → plugin webshell upload → command execution → cleanup.

承重组件(为什么这条链成立)

新颖之处在于组合,而非任何单个漏洞——各个组件本身都是合法的 WordPress 行为。为它们命名(依据 Adam Kues 的撰写)能让 exploit() 中伪造行的图变得可读,并标记出在入口点被修补后需要重新审计的内容:

  • 缓存/数据库协调——当内存中缓存的文章与其数据库行不一致时,WordPress 会通过 wp_update_post() 进行协调,并优先采用内存中的 post_type/post_status,从而让一个 oembed_cache 行被重新类型化为真正的 post/customize_changeset。
  • 保留 post_content 的循环检测——wp_insert_post_parent 过滤器会遍历父链;当检测到循环时,它会调用第二次 wp_update_post(),该调用修复父级而不覆盖 post_content。这是关键环节:它让伪造 changeset 的恶意 post_content 得以存活。(这就是为什么伪造行使用自父/互父循环。)
  • 通过 parse_request 重放钩子——发布文章会触发 do_action("{$status}_{$type}");一个带有 post_status=parse / post_type=request 的伪造行会触发 parse_request,在 changeset 假定的管理员身份(wp_set_current_user)仍然有效时重新运行批处理管道。

这些组件在已修补的 WordPress 中依然存在——只有两个入口点(批处理失步 + author__not_in 标量绕过)被关闭。任何能够伪造内存中文章缓存或写入 oembed_cache 行的新原语,都会重新启用完全相同的管理员接管尾部。

渲染时写入原语

全部四个渲染时写入原语均已在 7.0.1 上确认生效——每一个都作为未认证文章被伪造,通过批处理混淆进行渲染,并通过盲 SQLi 验证了产生的数据库写入:

原语触发标记汇点预测标识符已验证
oembed[embed]<url>[/embed]wp_posts 行(oembed_cache)post_name = md5(url+attrs)已创建文章 ID
rsswp:rss {feedURL}wp_options 站点瞬态_site_transient_feed_<md5(url)>option_id,缓存 5192 B
navigationwp:navigationwp_posts 行(wp_navigation)post_name = 'navigation'(固定)已创建 ID,slug 为 navigation
calendarwp:calendarwp_optionswp_calendar_block_has_published_postsoption_id,值为 '1'

每个结果所证明的内容:

  • oembed——参考原语:一个全新的 wp_posts 行,带有攻击者可预测的 slug(md5(url+serialize(attrs)))和真实的自动递增 ID。这是唯一能提供多个、按需、攻击者命名的文章行的原语——这就是为什么 RCE 链使用它来支撑伪造的 changeset/request 图。
  • rss——最强的通用写入:键 _site_transient_feed_<md5(url)> 完全可预测,存储的字节是攻击者 URL 所提供的 feed 正文——即攻击者同时控制键和值。这是一次 wp_options 写入(无文章 ID),因此它是一种选项投毒原语,而非 changeset 支撑的直接替代品。
  • navigation——唯一其他未认证的“渲染创建真实文章行”路径。它是单次触发的(如果存在任何已发布的 wp_navigation 则跳过),且 slug 固定,因此最多只能支撑一个伪造对象,不像 oEmbed 的 N 行。
  • calendar——确认渲染→update_option 路径在未认证情况下触发,但选项名称及其 '1'/'0' 值都是固定/数据库派生的,因此它只是一个“写入确实发生”的演示,攻击者对键或值没有控制权。

早期的条件链(已被上述默认配置链取代)

  • INTO OUTFILE webshell: 需要 WordPress 数据库用户拥有全局 FILE 权限 + 一个由 Web 提供的 secure_file_priv + 该目录对 Web 用户可读。在普通/托管主机上,这些条件均不成立。
  • SimplePie → WP_HTML_Token POP: call_user_func('wp_insert_user', user_data_array) — 需要 gc_enabled()=false + 有效的 HMAC(对精确序列化字节的 wp_hash,需要 wp-config.php 中的密钥)。

快速开始

要求:Docker + Docker Compose v2、Python 3.8+(仅标准库)、make、curl。

make up          # WordPress 6.9.4 (vulnerable) + MySQL 8.0, auto-installed on :8093
make check       # -> [VULNERABLE] http://localhost:8093 (WordPress 6.9.4 ...)
make proof       # -> also reads @@version and current_user() as read-only evidence
make exploit     # -> full pre-auth RCE: creates admin, deploys webshell, runs "id"
make patched     # rebuild on the fixed image and re-check -> [not vulnerable]
make down        # tear down (removes volumes)

使用 WP_PORT=8100 make up 更改端口。

关于已修补镜像的说明: 官方 Docker wordpress 镜像会比 WordPress 核心安全 版本晚一两天发布。如果 make patched 报告 wordpress:7.0.2 尚未在 Docker Hub 上, 请稍后重试,或将其指向已发布的任一修复标签: make patched WP_PATCHED_TAG=6.9.5(或 7.0.2 / 6.8.6)。任何 WordPress ≥ 6.9.5 / 7.0.2 / 6.8.6 都会返回 not vulnerable。

预期输出

$ make check
[VULNERABLE] http://localhost:8093  (WordPress 6.9.4, affected-full-chain)  [active=fired | method=boolean rows(true/false)=5/0 via x-wp-total | delivery=json | slot=users]
        confirmed: unauthenticated SQL injection
        rce: reachable on stock config; additionally requires no persistent object cache (not verified remotely -- the RCE PoC preflights it before writing)

$ make exploit
[*] seeding oEmbed caches ...
[*] extracting table prefix ...
[+] table prefix: wp_
[*] extracting admin user ID ...
[+] admin ID: 1
[*] recovering oEmbed cache post IDs ...
[+] cache IDs: [5, 6, 7]
[*] forging changeset + re-entry, creating administrator ...
[+] administrator created: w2s_...:W2s!...  ([email protected])
[*] logging in, deploying webshell, executing command ...
[+] vulnerable (unauth SQLi confirmed: method=boolean slot=users delivery=json)
[+] RCE output:

uid=33(www-data) gid=33(www-data) groups=33(www-data)

$ make patched
[not vulnerable] http://localhost:8093  (WordPress 7.0.2, outside-affected-range)  [active=negative | method=time fast=0.01s slow=0.01s delta=-0.00s | delivery=json | slot=users]

工具(wp2shell_check.py)

仅使用标准库,无依赖。

检测(默认)

非破坏性,在三个独立维度上自动回退,因此单条被阻断的路径绝不会被误判为假阴性:

  • oracle —— 首先使用快速的布尔行数差异(将注入的 WHERE 在 true/false 之间翻转,观察混淆后的 posts 查询的 X-WP-Total 是否塌缩,不使用 SLEEP);若未触发,则使用基于时间的 SLEEP 差异。SLEEP 被包裹在派生表中 —— (SELECT 1 FROM (SELECT SLEEP(n))x) —— 因此无论行数多少都只求值一次(裸 SLEEP() 在某些托管主机上会被优化掉,从而被误判为假阴性)。
  • delivery —— 首先向批量路由发送 JSON POST;若边缘节点阻断 /wp-json,则使用 POST / 上的 rest_route=/batch/v1 multipart 表单(即精确的运维请求形态)。
  • slot —— 首先针对 /wp/v2/users 验证偏移后的请求;若该端点对未认证调用者禁用(Disable-REST-API 插件、用户枚举加固),则回退到通用的 /wp/v2/posts/<id> 条目端点。

以上均不读取数据或改变状态。--proof 仅通过有界盲读读取 @@version 和 current_user()。它不会提取敏感数据或尝试代码执行。

下载工具