
关于wp2shell的大部分报道都止步于攻击者入侵网站这一步。这条攻击链最终成功将攻击者引入网站。但对于 WordPress 网站的管理者来说,真正重要的是攻击者入侵后几分钟甚至几天内发生的事情,而这部分内容却鲜有记录。
攻击链才是入口点,而非事件本身。
wp2shell 指的是 WordPress 核心漏洞CVE-2026-63030 和 CVE-2026-60137的关联攻击,这两个漏洞共同允许未经身份验证的攻击者对标准的 WordPress 安装执行远程代码。第一个漏洞是 REST 批处理端点中的路由混淆问题。第二个漏洞是 SQL 注入。这两个漏洞关联起来,使得攻击者无需任何插件、凭据或用户交互,WP_Query即可通过匿名 HTTP 请求访问攻击者创建的管理员帐户。
版本边界对于漏洞分类至关重要。Patchstack对该版本的技术分析指出,SQL 注入漏洞可以追溯到 WordPress 6.8,而导致其演变为未经身份验证的远程攻击的批处理处理程序混淆问题则是在 6.9 版本中才引入的。6.8 分支上的站点虽然存在注入漏洞,但无法通过此途径执行完整的远程代码。
WordPress于 2026 年 7 月 17 日发布了紧急版本 6.9.5、7.0.2 和 6.8.6,并启用了强制自动更新。CISA 于 7 月 21 日将该漏洞添加到其已知已利用漏洞目录中。漏洞披露后数小时内,就有用户报告称该漏洞已被利用,并在几天内出现了数十个可运行的概念验证实现。
我们调查的两个网站都在补丁发布后的48小时内遭到攻击,攻击源互不相关,且攻击间隔大约两小时。这个时间间隔值得注意。没有人专门针对这些企业。这只是扫描流量,寻找尚未修补的漏洞。
两次调查都未能最终确定第一次请求中使用的确切授权漏洞。这种局限性是结构性的,而非局部性的。标准的 Apache 和 NGINX 访问日志会记录请求行、状态码和 User-Agent,而任何广泛使用的日志格式都不会保留请求体、Cookie 标头、授权标头或 REST nonce。这些字段恰恰是识别漏洞机制的关键所在,但任何运行传统日志记录堆栈的主机都不会保留它们。
日志保留了事件发生的顺序,我们的团队也从中重建了事件的发生过程。在这两个案例中,大量 POST 请求涌入 WordPress REST 批处理路由,并返回了 HTTP 207 状态码,随后几秒钟内就创建了管理员帐户。在一个案例中,这些请求的 User-Agent 字符串与已公布的漏洞利用链名称相匹配。在同一案例中,原始管理员帐户在执行操作时并未记录到任何成功的登录事件,这符合未经身份验证的漏洞利用,而非密码被盗的情况。
证据与 wp2shell一致。但它不足以构成明确的归因,因此我们不作此判断。在没有请求级证据支持的情况下,断言某个特定的 CVE 导致了某个特定的安全漏洞,会导致错误的根本原因被记录在案,并导致错误的修复措施被优先考虑。
第一个有效载荷在不到半分钟内着陆
根据访问日志和 WordPress 活动记录重建的第一个站点的序列如下:
- 请求到达 REST 批量路由并返回 HTTP 207。
- 两秒钟后,攻击者的IP地址记录了网站原始管理员帐户执行的操作,该操作修改了一个不寻常的内部帖子记录。
- 一秒钟后,同一上下文创建了一个新的管理员帐户,其名称设计得像一个服务帐户。
- 八秒后,新账户成功登录。
- 11秒后,它上传了一个插件ZIP文件。
- 三秒钟后,插件安装并激活完成。
- 一秒钟后,攻击者从媒体库中删除了 ZIP 文件。
从开始到结束,大约用了 24 秒。第二个站点的形状相同,完成相同的序列大约用了 28 秒。
该插件在 WordPress 后台显示为一个安全实用程序,名称和版本号都看似合理。它的目录名称看起来像是一个合法的性能优化插件,只是附加了一个随机的十六进制后缀。任何快速浏览插件列表的人都会忽略它。
安装完成后13秒,攻击者直接请求插件的主PHP文件并执行了命令id && uname -a && hostname && pwd。该请求返回了HTTP 200状态码。至此,攻击者便以cPanel账户用户的身份执行了shell命令。
侦察结果揭示了黑客的活动
攻击者接下来检查的内容比任何恶意软件都更能说明其意图。我们的团队正是通过按顺序解读这些命令,才确定了此次攻击的目的。攻击者迅速使用 webshell 进行了以下测试:
- 系统 sendmail 二进制文件的位置和类型
- PHP 的
mail()函数是否可用 - 是否
proc_open()可用 - PHP 已禁用函数列表的内容
- 端口 25 上的出站 SMTP 是否可达
- DNS 和 MX 记录解析
- 邮件环境的行为是否类似于陷阱、丢弃或黑洞配置
最后一项检查很有意思。攻击者专门测试外发邮件是否真的能够送达,还是会被主机默默吞掉。这是对垃圾邮件基础设施的侦察。根据我们审查的证据,没有确认任何成功的外发邮件活动,但其意图并不明确。
第二个网站指向了不同的方向。它搭载了SEO伪装加载器,能够根据用户代理、来源网址、语言、IP地址、主机和请求URI提供不同的内容,并且具备URL重写能力robots.txt。这就是搜索结果投毒,它与垃圾邮件中继是不同的盈利途径。被入侵的WordPress网站通常会被用于重定向、注入脚本和窃取用户凭证,其目标并非仅仅是攻击者想要从服务器本身获取什么。
持久性由九个独立层构建而成
攻击者在获得命令执行权限后90秒,便在第一个站点上创建了一个每五分钟运行一次的定时任务。其目的是在主文件丢失时,从存储在上传目录下的备份副本中恢复恶意插件文件。
这是九层中的第一层。调查期间找回的全部物品如下:
- 攻击者在接下来的几天里,使用多个 IP 地址创建了多个管理员帐户。
- 恶意标准插件,以及在原始目录之外的三个额外目录,每个目录都包含可运行的 Webshell。
- 一款必备的插件守护者,它可以恢复已删除的文件,并且无法从 WordPress 控制面板中停用。
- PHP 副本位于 下
wp-content/uploads,名称与 WordPress 核心类文件类似 - 选项表中的编码有效载荷,以模仿合法站点健康瞬态的名称存储。
- 加载器块被注入到系统中
wp-config.php,读取数据库选项,解码存储的 PHP 代码,并将可执行文件写入磁盘。 - 账户的 CageFS 临时目录中存在五个可执行有效载荷。
- 额外的定时任务,五个独立的 30 分钟运行的条目,执行自检和恢复检查。
- 用于重建攻击者首选管理员帐户并销毁其他用户会话令牌的逻辑
请再次阅读该列表,并牢记清理步骤。移除插件后,定时任务仍会保留。移除定时任务后,数据库有效负载仍会保留。移除数据库有效负载后,wp-config.php用于重建数据库的加载器仍会保留。移除管理员帐户后,创建该帐户的 Webshell 仍会保留。
这九层恶意软件中只有两层存在于常规恶意软件扫描器能够检测到的位置。要找到其余层,需要读取解码后的有效载荷逻辑,并将其与 crontab 文件和选项表进行比对。
第二个网站增加了一个值得注意的变体:一个伪装成登录限制组件的必备插件,它会拦截wp_authenticate每次登录尝试,捕获用户名和明文密码,并通过区块链智能合约而非硬编码域名解析目标地址,并将凭据传输到远程端点。此外,它还会将自身从必备插件列表中移除,使其不会出现在控制面板中。
文件处于活动状态时,在该登录表单中输入的任何密码都会被泄露。密码未经哈希处理,也未被猜测,而是以明文形式读取。
清理与再次感染之间的六天
7月20日,来自另一个IP地址的活动删除了第一个网站上所有攻击者创建的管理员帐户,共四个。WordPress核心于当日更新至已修复漏洞的版本。
看起来清理工作很成功。恶意账户已被清除,漏洞已被修复,网站已恢复正常运行。
原有的webshell从未被移除。
7月26日,一个之前从未出现过的IP地址请求访问该插件文件。攻击者利用该文件编写了一个临时PHP辅助程序,该程序加载了WordPress环境,找到了现有的webshell,并将其复制到上传目录,创建了一个必须使用的插件守护程序,检查了攻击者首选的管理员帐户是否仍然存在,如果仍然存在,则重新创建该帐户,销毁了其他用户的会话令牌,然后删除了自身。
WordPress 将结果记录为新用户注册。但实际上并非注册,而是 PHP 以完整的应用程序权限运行,执行了网站自身代码被允许执行的操作。
该网站已完全收回。7月20日进行的补丁更新关闭了攻击者在7月18日使用的入口,而此时攻击者已经停止使用该入口。
备份文件已被篡改
从备份恢复是应对妥协的本能反应。但两项调查都发现,这种本能反应会失败。
一个账户携带了一个后门文件,该文件来自之前的托管服务提供商。它存在于导入到该账户的迁移备份中,其修改时间戳为 2025 年 8 月,并且还有一个账户级别的副本,其修改时间戳为 2025 年 10 月。该恶意软件比该账户在我们基础设施上的历史记录早了大约11 个月,之所以能够发现它,是因为调查人员检查了导入的备份树,而不仅仅是实时文档根目录。
现有证据无法证明2026年7月的攻击活动是否重新利用了之前的据点,我们也没有做出这样的假设。但可以确定的是,备份存档并不干净,而且自该网站上线之前就一直存在问题。
同一账户的维护插件回滚数据中包含一个随机命名的插件目录,其中存放着攻击周期代码。回滚数据不能用作干净的恢复源。正是通过检查回滚树而不是盲目信任它,才发现了这个问题。
还原点会恢复网站当时的所有内容,包括原本隐藏的内容。将网站恢复到已知入侵日期之前的某个日期,只是对入侵开始时间的一种猜测,而这两种情况下,这种猜测都是错误的。
自动更新未能到达以下网站之一
WordPress.org 强制对此次更新进行了自动更新,这通常是针对最严重漏洞才会采取的措施。第一个受影响的网站在 28 小时后仍然在使用存在漏洞的版本。
在修复过程中,我们的团队发现一个更新管理插件配置为阻止核心、插件和主题更新,并将其停用。该配置可能是紧急更新未能成功部署的一个合理解释,但更新日志不足以确凿地证明这一点。
对各机构而言,这是整个调查中最具实际意义的发现。在核心版本更新曾导致结账流程中断的网站上,阻止更新是一种正常且合理的选择。此外,这一决定也悄然让网站退出紧急安全更新,而且之后也不会有人再去考虑。如果您的维护堆栈包含更新管理器,那么就需要有人负责处理 WordPress 发布强制安全更新时应该如何处理的问题。
如何检查自己的网站是否存在这些指标
以下路径均相对于您的 WordPress 文档根目录。它们都不需要超出普通 cPanel 或 SFTP 帐户权限范围的服务器访问权限。活动文件名会轮换,因此请将这些模式视为比任何单个文件名都更持久的标识。
插件和主题目录名称
这两个账户都使用以下命名规则管理目录wp-content/plugins:
| 图案 | 它看起来像什么 |
|---|---|
wp2shell_* | 附加 8 个十六进制字符,与漏洞利用链的公开名称匹配。 |
wp2up_*,,nx_up_*h2ok_up_* | 独立文件上传器,附加 8 个十六进制字符 |
galex_* | Webshell 捆绑包,附加 8 个十六进制字符 |
| 合理的名称加上十六进制后缀 | 一个听起来很正规的插件标识符,但附加了一个随机的十六进制字符串。 |
最后一种模式能够绕过视觉扫描。一款恶意插件使用了一个类似于内容分发工具的别名,并在控制面板中显示为“安全标头管理器 2.1.4”,甚至还带有版本号。随机命名的主题目录也以同样的方式被使用。
必备插件
这些文件wp-content/mu-plugins不会出现在常规插件列表中,也无法从控制面板停用。其中发现的恶意文件包括一个名称模仿登录限制组件的凭据窃取程序、一个名称模仿网站修复工具的恢复保护程序,以及两个从随附压缩.gz包加载压缩有效载荷的短 PHP 文件。
打开该目录,并逐个检查其中的文件名称。在大多数网站上,列表应该很短或为空。
伪装成 WordPress 核心类的文件
辅助文件被写入插件目录,文件名按照核心命名规则复制:
class-wp-rest-compat-*.phpclass-wp-http-compat-*.phpclass-wp-cache-helper-*.phpclass-wp-widget-core-*.php
隐藏加载器使用以点号开头的文件,后跟十二个十六进制字符和一个.php扩展名。符合这些模式的文件不属于 WordPress,也不应放在插件目录中。1.php此外,一个帐户中还存在一个名为 JPEG 和 PHP 多语言插件的程序,以及一个名为 的旧后门程序,wp-mytrack.php该程序执行时会创建一个管理员帐户。
数据库指标
恶意载荷存储在选项表中,其名称与合法的站点健康条目名称并列,使用前缀_site_transient_health_后跟 8 个十六进制字符。您的表前缀将与默认值不同。WordPress 会创建真实的站点健康瞬态数据,因此请匹配末尾的十六进制字符串,而不仅仅是前缀。
配置指示器
标记为“已注入”的代码块WP_Core_Integrity被注入到数据库中wp-config.php。它们的功能是读取上述数据库有效载荷,对其进行解码,并将可执行的 PHP 代码写入帐户的临时目录。请打开wp-config.php并从头到尾阅读该目录。注释“停止编辑”之后的任何内容都值得关注。
在有效载荷中观察到的重复代码字符串包括_nx_auth,,_NX_PERSISTED和feature=selftest。
临时目录有效载荷
在一个账户的临时目录中发现了五个可执行文件,这些文件使用了 PHP 自带的临时文件命名规则:字符php后跟六个随机字母数字。这与 PHP 用于普通文件上传的模式相同,也正因如此,这些文件才能够混入其中。普通的临时上传文件会在请求结束后被删除。任何符合该模式且已存在数天的文件都值得仔细检查。
定时任务条目
检查账户的 crontab 文件,而不仅仅是 WordPress 的 cron 任务。一个账户包含一个五分钟的定时任务,用于从 uploads 目录下的备份副本中恢复已删除的插件文件,此外还有五个独立的三十分钟定时任务,用于执行自检。一个正常的 WordPress cron 任务只会调用上述wp-cron.php内容,不会执行其他操作。任何其他针对您网站的周期性 PHP 或 curl 调用都应该被记录下来。
用户帐户和令牌
- 管理员 ID 呈连续排列。一个账户中包含 38 个未经授权的管理员,这些管理员的 ID 呈连续排列。这种连续创建方式是一种结构性特征。
- 用户名模式。观察到的前缀包括
wpsvc_十六进制字符wp2_,以及由网站名称构成的帐户,并带有诸如_dev、_editor和之类的后缀_suporte。 - 应用程序密码。检查用户,然后检查每个配置文件,最后检查应用程序密码。攻击者创建的令牌包含
auto-bootstrap诸如 `<username>` 和 `<username>` 之类的名称bot-token。这些令牌在密码更改后仍然存在,并且无需登录表单。
日志签名
在访问日志中,查找向 HTTP 207 发送 POST 请求/?rest_route=/batch/v1或/wp-json/batch/v1返回 HTTP 207 状态码的请求,尤其要注意突发性请求。在一个账户中,这些请求携带了 User-Agent 字符串wp2shell。wp2shell-uploader在突发性请求发生后的几秒钟内创建管理员账户是需要查找的序列。
两个账户都呈现出相同的模式:先是快速发起一系列批量请求,然后向wp-login.php某个网站发送请求,接着成功登录,最后通过该网站上传插件并传递update.php参数action=upload-plugin。单独来看,上传插件是 WordPress 管理员的正常操作,并不显得异常。但如果紧接着从同一 IP 地址发起一系列批量请求,那就显得不寻常了。
请注意,User-Agent 字符串很容易更改,后续版本可能不会再使用它们。批量路由请求返回 HTTP 207 状态码才是更持久的信号。如果您的主机定期轮换或压缩访问日志,请在日志过期之前检索 2026 年 7 月中下旬的归档日志。
服务器响应检查(上传)
直接请求一个 PHP 文件(wp-content/uploads启用缓存清除),并确认响应。HTTP 403 响应是正确的。如果返回 HTTP 200 响应,content-type: application/octet-stream则表示该文件以可读源文件的形式提供,而不是被执行。
服务模式是两种故障模式中相对安全的一种,因为代码不会运行,但它仍然会将该文件的内容暴露给任何请求该 URL 的用户。两个账户都需要一条明确的拒绝规则来阻止上传的可执行文件扩展名,并且两个账户都已添加了这样的规则。我们通过在服务器外部使用清除缓存的请求,并使用普通浏览器用户代理、Googlebot 等工具进行测试来发现这个问题,因为某些配置在不同客户端上的响应有所不同。如果仅使用单个浏览器进行测试,则会遗漏这个问题。
硬化值确认
wp-config.php权限设置为0600- 任何合法的 PHP 上传文件都设置为0600
DISALLOW_FILE_EDIT并被DISALLOW_FILE_MODS定义为真FORCE_SSL_ADMIN定义为真- 文档根目录中不存在全局可写文件、其他帐户拥有的文件以及意外的符号链接。
经过核实的清理工作究竟包含哪些内容?
这两个账户的修复工作都遵循相同的结构。这就是这项工作的框架,也是评估任何清理工作的合理基准,无论清理工作是由公司内部人员执行还是由供应商执行。
首先进行隔离。调查期间,第一个站点被屏蔽为 HTTP 403错误。清理一个仍然可以访问的站点意味着要争分夺秒地执行每五分钟运行一次的恢复机制。
删除前务必保留。所有恶意文件、数据库有效载荷、用户记录、定时任务和配置文件在删除前均已归档并进行哈希处理。如果删除恶意软件时未保留相关数据,则无法回答后续问题,包括清理是否成功的问题。
逐层移除,然后逐一验证。文件系统、数据库选项、wp-config.php注入、定时任务条目、临时目录、必备插件、上传文件和用户记录均已清理并分别确认。
验证核心和软件包的完整性是否与官方校验和一致。两个站点的核心均已验证。在第一个站点上,调查发现插件校验和不匹配,并从可信软件包重新安装了该插件;此外,还从官方软件包替换了两个包含已修改文件的主题,而不是直接进行修补。
轮换攻击者能够读取的所有数据。攻击者可以利用 PHP 命令执行和数据库访问权限,读取wp-config.php配置文件、选项表以及存储在其中的任何凭据。这意味着 WordPress 管理员密码、cPanel、FTP 和 SFTP、SSH、数据库、SMTP、支付处理器密钥以及网站持有的所有第三方 API 令牌都可能被读取。两份报告均指出轮换数据是必要的,而非推荐的。
精简并确认管理员列表。一个网站的管理员数量从 38 个未经授权的账户减少到 3 个现有账户。所有剩余账户都需要网站所有者确认其已获得授权,确认时需提供账户名称。
销毁会话和应用程序密码。攻击者创建的 WordPress 应用程序密码,其名称与自动化令牌相似,无需用户访问登录表单即可提供身份验证。大多数网站所有者从未打开过个人资料中的登录页面。即使更改密码,这些密码仍然有效。
之后要建立基线。第一个站点修复后的基线记录了超过 36,000 个可执行文件和配置文件的哈希值。如果没有已知良好的基线,下一次调查就得从零开始。
本周机构和开发商应该做出哪些改变
三项具体措施,按风险消除程度排序:
逐个确认您管理的每个站点上已安装的 WordPress 版本。不要轻信更新控制面板,也不要想当然地认为强制更新已经生效。安全研究人员一直指出,即使禁用了自动更新或自动更新失败,站点仍然可能存在安全隐患。请检查版本字符串,然后检查插件堆栈中是否有任何设置阻止了更新。
同时审核管理员帐户和应用程序密码。恶意管理员很容易被发现,而与合法帐户关联的应用程序密码则不易察觉,因此它最有可能在仓促清理后幸存下来。在每个站点上检查这两项,然后检查必须使用的插件目录,该目录根本不会出现在常规插件列表中。
任何已确认的泄露事件都应视为完整的凭证轮换事件。如果攻击者拥有该账户的 PHP 执行权限,则该账户可访问的所有密钥都将暴露。部分轮换则能确保密钥仍然可用。
二次感染是部分清理后的正常结果,并非罕见现象。第一个污染场地清理间隔了六天,在这六天里,场地看起来很干净,装载正常,并且通过了例行检查。
这类调查实际需要哪些条件
这两项调查均由内部团队在我们拥有并运营的、分布在三个数据中心区域的基础设施上完成。所有工作均未外包给扫描供应商,分析工作也未交给任何第三方。
这一点至关重要,因为它关系到恶意软件的隐藏位置。商业恶意软件扫描器可以找到文件,但它无法解码存储在选项表中、名称模仿合法网站健康状态瞬态数据的有效载荷。它也无法追踪注入到wp-config.php可执行文件中的加载器块,这些加载器块会在帐户的临时目录中重建这些可执行文件。它也无法注意到,三周前某个请求结束时,本应删除的五个符合 PHP 正常上传命名规则的文件却并未被删除。
这些发现源于工作人员对代码的解读,以及对已存档的访问日志、WordPress 活动记录和账户定时任务中的日志时间戳进行比对。我们支持团队的每位工程师在处理一级支持请求之前,都要完成超过 280 小时的培训,平均支持经验超过五年。这些团队提供 24/7 全天候服务,本文背后的调查工作均由您可以通过电话联系到的人员完成。
这与我们处理基础设施层威胁的方式一致。2026 年 4 月,cPanel 和 WHM 的一个关键预认证漏洞被披露后,我们的网络运维团队在数小时内封锁了所有三个数据中心区域的网络边缘,然后逐台服务器地进行了修补。WordPress 核心更新是直接部署在应用程序内部,而不是服务器堆栈上,因此,此类安全漏洞需要不同的应对措施和不同的调查方法。
如果您为客户管理 WordPress 网站,但不确定之前的清理是否彻底,那么这种不确定性就是我们需要发现的问题。请将您的帐户交给我们,我们将逐层进行检查,而不仅仅是文件系统。

