Aioga
AI资讯 / 行业动态
返回 AI资讯

利用 GPT-5.6 发现 WordPress RCE 漏洞,中介报价 50 万美元,作者仅售 25 美元

Hacker News 热门(buzzing.cc 中文翻译)Aioga 编辑团队2026-07-20T10:47:09.626Z热度 38

漏洞中介为 WordPress 远程代码执行(RCE)漏洞开出 50 万美元收购价。一名安全研究者利用 GPT-5.6 发现了一个此类漏洞,却仅以 25 美元的价格出售。该事件...

行业动态Hacker News 热门(buzzing.cc 中文翻译)

今日 AI 情报摘要

漏洞中介为 WordPress 远程代码执行(RCE)漏洞开出 50 万美元收购价。

一名安全研究者利用 GPT-5.6 发现了一个此类漏洞,却仅以 25 美元的价格出售。 该事件凸显了 AI 辅助漏洞挖掘能力与漏洞定价之间的巨大落差。

中文正文 · AI 翻译

如果你正在运行 WordPress 并且想检查你的实例是否容易受到攻击,你可以使用我们托管在这里的工具:https://wp2shell.com/:https://wp2shell.com/。

我们推迟发布这个问题,以给防御方一个在周末升级其 WordPress 实例的机会,但在此期间,Calif:https://x.com/calif_io/status/2079016161891521022 和 Hacktron:https://www.linkedin.com/feed/update/urn:li:activity:7484494074658512896/ 能够在其他 PoC 出现在 GitHub 上之前独立重现整个链条。

像大多数安全研究人员一样,我们非常密切地关注 Searchlight Cyber 的新模型发布。当 GPT5.6 Sol Ultra 发布时,我们非常兴奋地测试它。

我曾读到 Sol 最近解决了一个著名的数学猜想——循环双覆盖猜想:https://en.wikipedia.org/wiki/Cycle_double_cover。作为安全研究人员,对我来说有趣的是 OpenAI 发布了他们使用的提示词,这里有官方发布链接:https://cdn.openai.com/pdf/04d1d1e4-bc75-476a-97cf-49055cd98d31/cdc_prompt.pdf。我在安全社区中没有看到有人谈论过它或者真正提及它,但我认为如果这个提示词足够好去解决困难的数学问题,它大概也足够用于安全研究。我采用了这个提示词并进行了调整,然后将其指向 WordPress,并要求它使用 4 个代理至少运行 6 个小时。以下是我最终使用的精确提示词:

我使用的文件夹结构如下:

在开始之前,我将最新的稳定版本 WordPress 克隆到 main/ 目录中,并删除了 .git 目录。我这样做是因为我经常发现,在进行安全研究时,LLM 会查看更改历史或互联网寻找线索,而对于新型漏洞发现,我个人认为这是浪费 token。这也是我添加以下这行代码的原因:

我的经验还表明,模型有时会为了达成你的要求而“作弊”,要么选择极不可能的配置选项,要么编造攻击者无法实现的前置条件。这就是为什么我非常明确地指出,它应该是在典型生产部署的 MySQL 环境下进行的预认证 RCE。

最终,我发现模型并不会真正‘深挖’底层库,即使有这个需要。它们的第一反应是,如果不知道,就去搜索有关某个 API 或 PHP 函数的信息。但模型在阅读源代码方面非常擅长,所以我只是让它们去阅读源代码:

提示的其余部分几乎完全取自 OpenAI 的 CDC 提示。

当我回来时,我在其运行输出中看到,它声称发现了一个预先认证的 SQL 注入漏洞。起初我并不完全相信,毕竟 WordPress 是有史以来防护最严格的目标之一,而且本十年也没有出现过任何有意义的预认证漏洞。但当我了解它所做的事情时,我意识到它确实发现了完全预认证的 SQL 注入漏洞。仍然不完全相信,我在一台远程服务器上安装了一个默认的 WordPress 实例,并让它窃取管理员的邮箱。几分钟之内,它打印出了我用来设置该实例的邮箱。

从那时起,我问 Sol 是否可以将此升级为远程代码执行 (RCE)。大约 4 小时后,Sol 给出了肯定的答复:预认证的只读 SQL 注入可以可靠地用于提升权限到管理员级别,而无需破解任何密码或进行任何离线计算。

总使用量:每周使用量的 50%。按 200 美元订阅的比例总成本:约 25 美元美金。

此时,我意识到我在全球最受欢迎的软件之一的默认配置中发现了一个漏洞。估算不一,但大多数人同意全球运行的 WordPress 实例超过 5 亿个。

接下来的这一天,我花时间理清 Sol 做了什么,并准备将报告发送给 WordPress。虽然 SQL 注入相对容易理解,但 Sol 为将其升级到远程代码执行所做的后利用工作完全令人难以置信。Sol 可能只花了 4 小时来编写,但我理解它却花了远远更长的时间。下面是我(人类)对该漏洞的描述:初始漏洞、SQL 注入以及用于升级到远程代码执行的后利用链。

WordPress 批量 API 于 2020 年的 WordPress 5.6 中引入,允许用户在一次请求中发起多个虚拟 API 请求。无论是否已通过身份验证,你都可以访问此端点,但每个子请求都会传递该身份验证信息。使用它的一个简单例子是一次性更新多个博客文章的标题或标签;这是一个简单的例子:

如果你直接访问一个端点,例如 POST /wp-json/wp/v2/posts,WordPress 有一个大致如下的验证流程:

这意味着流入端点回调本身的任何参数已经被验证为正确的形状和数据类型。API 端点本身在多个地方依赖此验证,以确保例如,文章 ID 是整数,文章标题是字符串等。因此,能够绕过参数净化过程是非常重要的。

批量 API 的处理方式略有不同。它并不是像你预期的那样依次运行上述四步流程,而是将验证和执行批量处理成两个循环,如下所示:

这是在 class-wp-rest-server.php 中通过两个数组实现的,一个用于匹配($matches),一个用于验证($validation)。意图是 matches 数组中的每个索引 $i 对应 validation 数组中的同一索引。因此 $validation[0] 包含 $matches[0] 的验证,$validation[1] 包含 $matches[1] 的验证,依此类推。验证过程如下:

你发现这里的漏洞了吗?如果我们取 is_wp_error( $single_request ) 分支,$validation 数组会被更新,但由于 continue;,matches 数组不会更新!假设第一个请求是格式错误的。原始请求及其验证结果保持对齐,但 $matches 中的每个条目都向后错位一个位置。第二个执行循环会跳过索引 0 的错误。在索引 1,它使用索引 1 的原始请求及该请求的验证结果,但 $matches[1] 现在包含的是索引 2 的原始请求所匹配的处理器。$matches[0] 从未被使用。这使我们能够验证一个请求,然后使用下一个请求的端点处理器来执行它。

使用这个方法,我们可以通过将每个端点与不同端点的验证匹配来绕过所有批处理启用端点的所有数据清理,这些不同的端点不会对相同的参数进行清理。但我们可以在哪里使用它呢?

路由 GET /wp/v2/posts 允许用户列出符合特定条件的帖子。该 API 提供了从结果中排除作者 ID 的功能:

这里有一个严重的漏洞。如果 author__not_in 输入的是数组,它会使用 absint 过滤每个项,将其清理为整数。但如果输入是标量,它将保持不变。因此,提供像 "foobar" 这样的标量字符串会直接插入原始 SQL 查询中而没有任何转义。

直接调用此路由时,这通常不会是问题,因为公共 author_exclude 参数必须是整数数组。帖子控制器仅在验证后将其映射到 author__not_in。然而,通过批处理 API,我们有验证/执行不匹配的问题,使我们可以巧妙地绕过参数验证。让我们试一试:

这里我们应用到目前为止的方法。首先,在请求中使用了一个无效路径,以不同步路径和主体验证。author_exclude 参数在 DELETE /wp/v2/posts/1 路由上进行验证,而该路由没有对其进行验证(它不识别该参数),但是,由于我们的不同步,author_exclude 被应用到 GET /wp/v2/posts 上。只有一个问题:

批处理 API 不支持 GET 请求。我们发现的 SQL 注入只能通过 GET 访问,所以似乎我们遇到了死胡同。Sol 的解决方案非常巧妙且具有启发性。该模型意识到请求方法的验证本身是作为参数验证实现的。我们有绕过参数验证的方法吗?有!我们可以利用不同步漏洞!因此,Sol 构造了一个载荷,在其中递归调用批处理端点。在内层调用中,由于不同步,未对请求方法进行验证。然后我们可以发起 GET 请求。预认证 SQL 注入的最终载荷就是:

在这里,我们利用批处理 API 验证漏洞进行了两次递归攻击。在外层请求中,我们使其不同步,以至于 method 字段未被验证。然后在内层请求中,我们再次使其不同步,使 author_exclude 字段未被验证。有效负载 0) OR 1=1 -- 将返回所有帖子行,确认注入成功。从这里开始,基于 UNION 的注入可以通过返回一个完整的 wp_posts 形状的行来泄露任意数据库值。

此时,我们在 WordPress 中已经拥有一个预认证 SQL 注入漏洞,这已经是一个大问题。然而,受到 LLM 强大功能的启发,我问它是否能够将此升级为全面的 RCE(远程代码执行)。

我的第一本能是泄露像密码、重置令牌或 API 密钥之类的东西,以便提升权限。然而,WordPress 有一个相当完善的安全模型,所有这些都在数据库中被哈希处理。除非管理员的密码特别弱并且可以被破解,否则仅仅泄露数据库是不足以接管管理员账户的。然而,Sol 很快发现了另一个有希望的角度:

WordPress 的性能非常高。作为其中的一部分,WordPress 在请求生命周期中会维护 WP_Post 对象的内存缓存。这些缓存不会持久化;请求结束后,这些缓存对象会被丢弃。然而,如果在请求生命周期中多次引用同一篇文章,WordPress 会在首次从数据库取回后使用缓存的文章。这避免了如果同一篇文章在同一次请求中被多次使用时的多次数据库往返。例如,用户可能访问 ID 为 10 的文章,但同时,侧边栏小部件列出了包括文章 ID 10 在内的最近 5 篇文章,等等。

由于我们在 posts 端点中有一个 SQL 注入漏洞,我们可以使用基于 UNION 的注入来“伪造”返回的帖子。由于这些帖子会被缓存,我们对缓存的帖子数据有极大的控制权限。此外,WordPress 在渲染文章文本之前会进行后处理,即使通过 API 渲染,我们也能完全控制返回的文章文本。

即使我们可以污染请求缓存,也不太明显我们可以用这个原语做什么。毕竟,我们返回的假帖子并不是真正由数据库支持的帖子,这限制了跨请求的影响。看起来我们无法将这些假帖子变成真实的数据库行——除了……

WordPress 有一个叫做 embeds 的功能:https://wordpress.org/documentation/article/embeds/。在文章中包含类似 [embed]https://example.com[/embed] 的结构,如果远程页面的内容是 WordPress 支持的格式,该内容将被嵌入到你的文章中。

为了避免每次加载文章时都发起 HTTP 请求,WordPress 不仅在内存中缓存这些嵌入内容,而且也在数据库级别进行缓存。这以 oembed_cache 类型的帖子形式存储在数据库的 wp_posts 表中。

WordPress 帖子是另一种受支持的嵌入类型。如果你嵌入一个帖子并提供相对路径而不是绝对 URL,WordPress 会识别该 URL 指向的是本地帖子,而实际上不会发起 HTTP 请求。然而,WordPress 实际上不会检查嵌入中所引用的帖子 ID 是否存在。因此,放置类似 [embed width="500" height="750"]/?p=10[/embed] 的文本,将会生成一个类型为 oembed_cache 的数据库行,其中包含帖子 10 的嵌入数据。假设新行的 ID 是 11。

现在我们在数据库中有了帖子 ID 为 11 的行,事情开始变得有趣。如果我们再次滥用同样的 SQLi,我们可以在内存中再次伪造任何我们喜欢的帖子内容,并且这些内容将存储在每请求的内存缓存中。然而,这一次,内存中的帖子版本和数据库缓存的版本不一致。WordPress 会识别这一点,并尝试调和两个版本:

在这里,ID 和 post_content 在写入数据库之前就已设置。然而,帖子还有许多其他字段,例如 post_status 和 post_type。在数据库中,post_type 是 oembed_cache,但使用我们的 SQLi,我们可以伪造任何我们想要的帖子类型,例如 post(这是一篇普通的 WordPress 帖子)。如果数据库行和内存缓存不一致,WordPress 会优先使用内存中的字段,而这些字段我们完全可以控制。因此,我们可以强制 oembed_cache 行变成普通帖子,从而突然‘出现’。我们唯一无法控制的是 post_content——因为它在调用 wp_update_post 时被明确指定,我们无法覆盖它。

用帖子篡改网站很有趣,特别是考虑到我们能够在仅 SELECT 的 SQLi 中凭空伪造它们。但这不是 RCE。下一步是什么?Sol 锁定了一种特殊类型的帖子,称为 customize_changeset。

当你在 WordPress 中草拟对网站主题的编辑时,它需要以某种方式将这些草拟的更改保存到网站设置中。它所采用的方式是在 wp_posts 中使用一行特殊记录,post_type 设置为 customize_changeset。它不是将整个网站设置保存为一个 blob,而是将更改字段的差异存储在 post_content 中。一个示例可能如下所示:

如果你继续编辑网站主题,WordPress 将临时应用该 changeset,使你能够从上次停止的地方继续编辑。如果你发布更改,这些更改将永久应用到网站。

帖子中可以更改的每一项都有一个键(例如 blogname)和一个三元素字典:你正在更改的内容类型、更改的值以及用于执行更改的用户 ID。在我们的例子中,更改的用户 ID 是 1,因此它们将用管理员权限应用。当应用 changeset 时,WordPress 会暂时根据 changeset 中指定的 user_id 设置当前用户:

因此,如果在我们以匿名用户身份时应用了一个更改集,我们可以暂时假设管理员的身份。有一个主要问题:如前所述,更改集使用 post_content 字段来存储更改集的 JSON。这是目前我们作为攻击者使用缓存中毒技巧无法控制的唯一字段,因为在前面提到的 wp_update_post 调用中,post_content 被显式地覆盖为嵌入内容。然而,Sol 发现了一个小工具,它将迫使 WordPress 协调这些冲突的缓存表示。

WordPress 允许文章有父级。这意味着你可以把 WordPress 文章集看作一棵树,每篇文章有零个或一个父级。在这里,我们用箭头从子节点指向父节点:

然而,WordPress 不允许存在环。对于许多操作,如果 WordPress 对文章应用更改,它会调用过滤器 wp_insert_post_parent,该过滤器会遍历到文章的父级、父级的父级,依此类推,直到到达树的顶端。这意味着如果文章层级被某种方式破坏并且文章图存在循环,WordPress 可能会陷入无限循环:

这与页面层级相关。如果你让一篇文章成为它自己的父级,可能会引发许多问题。

WordPress 已预料到这种情况,并添加了循环检测逻辑。如果 WordPress 在更新文章层级时检测到循环,它会将文章的父级 ID 更新为零:

这是与前面 wp_update_post 不同的调用。重要的是,这次调用不会覆盖 post_content,因此我们可以使用 SQLi 控制通过内存中伪造的文章的 post_content。因此,我们可以伪造一个合法的 customize_changeset,其中包含与管理员用户关联的 JSON。这允许我们以管理员身份修改其他文章。然而,一旦对其他文章的更改完成,我们的权限就会恢复为访客。我们如何从能够更改文章内容,转变为能够以管理员身份做任何事情?

为了支持其丰富的插件生态系统,WordPress 有一个名为 hooks 的功能:https://developer.wordpress.org/plugins/hooks/。这些钩子,名称像 wp_enqueue_scripts 或 publish_post,允许插件‘挂接’(顾名思义)WordPress 生命周期的几乎每一个部分。钩子分为动作(可以调用但不返回值的东西)和过滤器(返回值的东西)。例如,插件作者可能希望添加功能来记录所有用户登录,并使用钩子来实现:

动作钩子也可以通过 do_action() 手动调用。在用户登录时,WordPress 并不仅仅调用一些内部的 ->wpLogin() 函数,而是使用 do_action('wp_login', $username, $user_obj)。这种动态派发在整个代码库中无处不在,这也是 WordPress 如此可定制的原因。

当发布文章时,WordPress 允许用户挂接该发布事件。他们通过调用实现:

在合法情况下,文章的状态可能已从 draft 变为 publish,因此动态动作将被调用为 publish_post,插件可以挂接它。Sol 意识到在我们假设临时管理员角色时,该界面是可访问的,并且还意识到因为我们在内存中伪造了整个文章,new_status 和 $post->post_type 可以对应任何我们想要的内容,并不一定非得对应合法的 post_type 或状态。这允许我们作为攻击者,只要动作名称至少包含一个下划线,就可以以管理员身份调用任何动作。

主要问题是 $post->ID 在我们的控制之下,但它仅仅是一个 ID。此外,$post 是一个 WP_Post 对象。这意味着我们几乎无法控制传递给动作的参数。Sol 又想出了一个策略来解决这个问题:它针对 parse_request 钩子。这个钩子在请求生命周期的最开始被调用,几乎在任何操作之前。因此调用 parse_request 将从头开始重放整个 Batch API 请求,只是我们仍然拥有临时假设的管理员角色。

现在我们拥有了所有步骤,让我们来制作利用程序。

最终的漏洞利用会发出两个请求。为了清晰起见,我们将漏洞利用中使用的每个帖子ID称为一个字母,例如C或O。实际上,这些字母变量可以被任何ID替代,只要该ID足够大,不会与目标系统中已存在的合法ID冲突。

在第一个请求中,我们给数据库“播种”3行oembed_cache,分别对应帖子O、C和D。我们通过利用SQL注入返回一个ID为零的伪造帖子,并包含三条指向S的嵌入链接来实现:

[embed width="500" height="750"]/?p=S&wpsec_seed=foobar-outer[/embed] [embed width="500" height="750"]/?p=S&wpsec_seed=foobar-changeset[/embed] [embed width="500" height="750"]/?p=S&wpsec_seed=foobar-dispatch[/embed]

这三个URL都指向同一个S,但额外的查询字符串标记不同。因此,它们生成三个不同的oEmbed缓存哈希。这三个哈希标识未来的O、C和D行。

对于第二个请求,我们需要六个伪造帖子,构造如下:

在SQL注入执行的此时点,WordPress的状态如下:

伪造帖子T触发了执行。它包含一个指向S的嵌入,由于请求是本地嵌入且哈希对应O,因此会调用get_post(O)。该请求由数据库中的一行支撑,而O是由帖子S支持的嵌入(正如我们在第一个请求中播种的那样)。S在数据库中不存在,不是一个真实的帖子,但这没关系,因为它在内存中的帖子缓存中。由于我们在O上放置了一个伪造的post_modified_gmt,WordPress会认为S的数据缓存已过期,因此会调用get_post(S),从伪造的内存版本S中返回数据。S的数据将被嵌入例程转换成适合嵌入的内容。

情报判断

Aioga 编辑摘要

Aioga 编辑摘要:漏洞中介为 WordPress 远程代码执行(RCE)漏洞开出 50 万美元收购价。 Aioga 将其归入「行业动态」方向,重点关注它对真实使用和行业竞争的影响。

背景分析

背景分析:公司与行业类动态需要放在竞争格局、商业化路径、资本信号和监管环境中观察,单条公告不能代表最终结果。

Aioga 观点

Aioga 判断:这条动态更适合作为行业观察信号,当前信息足以建立线索,但不足以推导长期结论。

影响与后续

影响分析:对相关团队而言,短期应先核对来源、可用范围和实际成本,再判断是否值得接入或跟进。 后续观察:继续观察官方文件、合作落地、收入或用户信号、竞品动作和监管后续。

来源与版权说明

本页正文由公开来源页面提取并按原有信息整理,同时保留来源、发布时间和原文入口。版权归原作者及来源网站所有,请通过原文链接核验和阅读来源版本。

抓取通道: 摘要聚合 · 原始域名: slcyber.io

来源: Hacker News 热门(buzzing.cc 中文翻译)

原文链接: 打开原始来源

Aioga 归档: 查看情报页

Content record: source-page · Updated: 2026-07-20T10:47:09.626Z

API 中转站
API RELAY · DEVELOPER INFRASTRUCTURE

API 中转站

统一接入主流 AI 模型 API,为开发、测试与生产环境提供稳定调用入口。

立即访问 api.w173.com
AIOGA SHARE POSTER

分享这篇 AI 情报

漏洞中介为 WordPress 远程代码执行(RCE)漏洞开出 50 万美元收购价。一名安全研究者利用 GPT-5.6 发现了一个此类漏洞,却仅以 25 美元的价格出售。该事件...

Hacker News 热门(buzzing.cc 中文翻译)2026-07-20T10:47:09.626Z
扫码打开文章详情扫码直达文章详情

Aioga 自动聚合全球 AI 动态,并保留来源信息用于核验与引用。