Skip to content
KitploitKITPLOIT
工具博客
Log in
提交
工具博客
提交

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

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

订阅源联系隐私© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
CVE-2026-64638 — CVE-2026-64638 的概念验证漏洞利用:WordPress 登录中的反射型 XSS 与 DOM clobbering 链式利用,可实现管理员账户接管和远程代码执行。 | Kitploit
工具/GitHubGitHub/dungsocool/cve-2026-64638
钓鱼工具漏洞分析代码分析漏洞利用Web应用程序漏洞利用Web安全Payload 开发
GitHubdungsocool/cve-2026-64638

CVE-2026-64638

CVE-2026-64638 的概念验证漏洞利用:WordPress 登录中的反射型 XSS 与 DOM clobbering 链式利用,可实现管理员账户接管和远程代码执行。

查看仓库
221个月前尚未审核

最受欢迎

查看全部 →

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

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

CVE-2026-64638

登录页面上的反射型 XSS 导致 PHP 代码执行——WordPress Core

软件: WordPress Core ≤ 7.0.2(7.0.3 之前的所有版本)

CVSS: 8.9(高危)

CWE: CWE-79——网页生成期间输入未正确中和

所需认证: 无(预认证)

用户交互: 主动(管理员需点击 1 个链接)

影响: XSS → 账户接管 → 远程代码执行


1. 这是什么漏洞?

WordPress 是全球最流行的内容管理系统,占互联网上所有网站的 40% 以上。每个 WordPress 站点都有一个位于 /wp-login.php 的登录页面——这是一个公共端点,任何人都可以在无需认证的情况下访问。

当用户输入错误的用户名时,WordPress 会显示一条包含用户刚输入的确切用户名的错误消息:“用户名 X 未在此站点注册。” 问题在于,用户名值被直接放入 HTML 响应中,未经过任何转义函数——攻击者只需输入 HTML/JavaScript 而不是真实用户名,代码就会在浏览器中执行。

这是一个反射型 XSS 漏洞——载荷包含在请求中,服务器将其原样反射回 HTML 中。其危险之处在于该漏洞位于登录页面——管理员经常访问的地方,管理员的会话 Cookie 可能在此被窃取。

研究团队进一步发现,此 XSS 可与 WordPress emoji-loader 中的 DOM clobbering(DOM 覆写)漏洞链式利用,从而允许从外部服务器加载 JavaScript。以此为基础,攻击者可以创建新的管理员账户 → 安装包含 WebShell 的插件 → 在服务器上执行 PHP 代码。此利用链被称为 XSS2Shell。

属性值
CVE 编号CVE-2026-64638
CVSS 评分8.9(高危)
软件WordPress Core ≤ 7.0.2
认证无需认证(预认证)
用户交互需要 1 次点击(管理员点击链接)
攻击复杂度高
已修复版本WordPress 7.0.3(08/06/2026)
报告者pwn.ai 团队,通过 HackerOne
HackerOne 报告#3877102

2. 术语解释

DOM Clobbering 与 emoji-loader

WordPress 通过文件 emoji-loader.js 在每个页面(包括登录页面)加载 emoji 支持。此脚本从具有 id="wp-emoji-settings" 的元素中读取配置:

// Before patch (vulnerable)
const settings = JSON.parse(
    document.getElementById('wp-emoji-settings').textContent
);

document.getElementById() 返回 DOM 中具有匹配 id 的第一个元素。如果攻击者在原始 script 标签之前注入一个 <div id="wp-emoji-settings">,getElementById 将读取攻击者的内容而不是真实配置。这种技术称为 DOM clobbering——通过注入 HTML 元素来覆盖 JavaScript 行为。

emoji 配置包含一个用于加载 JavaScript 文件的 URL(concatemoji)。攻击者控制此 URL → 从外部服务器加载 JS 文件 → 在浏览器上下文中执行任意代码。

从 XSS 到 WordPress RCE

一旦在管理员上下文中实现 JavaScript 执行,攻击者就拥有完整的 WordPress 管理员权限:

  1. 创建新的管理员账户——使用管理员会话调用 /wp-admin/user-new.php
  2. 安装包含 PHP 代码的插件——通过 /wp-admin/plugin-install.php 上传插件
  3. 修改主题文件——通过主题编辑器插入 PHP 后门

以上 3 种方法中的任何一种都允许在服务器上执行 PHP 代码——即 RCE。

3. 源码分析——根本原因

第 1 步:定位 Sink——用户名被放入 HTML 的位置

从 wordpress-develop 上的修复提交 0d6d42e 中,我确定了 wp-includes/user.php 文件中 3 个将用户名/邮箱直接放入错误消息的位置:

# View diff between vulnerable and patched versions
git diff 7.0.2..7.0.3 -- src/wp-includes/user.php

位置 1——第 189 行(用户名不存在):

修复前:

// BEFORE (vulnerable):
sprintf(
    __( 'The username <strong>%s</strong> is not registered...' ),
    $username      // ← no escaping
)

image.png

修复后:

// fixed:
sprintf(
    __( 'The username <strong>%s</strong> is not registered...' ),
    esc_html( $username )    // ← escaped
)

位置 2——第 216 行(密码错误):

修复前:

image.png

// BEFORE:
'<strong>' . $username . '</strong>'    // ← no escaping

修复后:

// AFTER:
'<strong>' . esc_html( $username ) . '</strong>'

位置 3——第 299 行(邮箱密码错误):

修复前:

image.png

// BEFORE:
'<strong>' . $email . '</strong>'    // ← no escaping

修复后:

// AFTER:
'<strong>' . esc_html( $email ) . '</strong>'

第 2 步:追踪 Source——数据来自何处?

从 POST 请求到错误消息的数据流:

$_POST['log']                           ← user input from login form
    ↓
wp_signon() [user.php:51]
    $credentials['user_login'] = wp_unslash($_POST['log'])     ← only removes backslashes
    ↓
wp_authenticate($username, $password) [pluggable.php:689]
    $username = sanitize_user($username)     ← strips HTML tags, but has a bypass
    ↓
wp_authenticate_username_password() [user.php:153]
    get_user_by('login', $username)          ← user not found
    ↓
    sprintf('The username <strong>%s</strong>...', $username)   ← XSS!
    ↓
WP_Error → login_header() → wp_admin_notice()
    wp_kses_post(...)     ← filters HTML but allows <div>, <a>,  through
    ↓
HTML response → browser render → JavaScript execute

第 3 步:两层防御、薄弱点与调试验证

在用户名到达 HTML 之前,WordPress 有 2 层过滤:

第 1 层:sanitize_user()——调用 strip_tags() 移除 HTML 标签。然而,PHP 的 strip_tags() 存在已知限制:非标准标签格式可以绕过过滤器。

第 2 层:wp_kses_post()——允许安全 HTML 子集通过,包括带有某些属性的 <div>、<a>、``(但会剥离 onerror、onload 等事件处理属性)。关键点:wp_kses_post 允许 <div id="wp-emoji-settings">——这正是 DOM clobbering 所需的元素。

pwn.ai 团队找到了一种绕过这两层过滤以注入有效载荷的方法。具体技术细节尚未公开披露。

使用 Xdebug 调试——数据流确认

为了直观确认用户名未经转义就直接进入 HTML,我使用 Xdebug + VS Code 在执行链的关键位置设置断点。

第 1 步——在登录表单中输入 XSS 载荷:

访问 http://localhost:8282/wp-login.php,输入用户名 ``,然后点击“登录”。出现弹窗——XSS 生效。

image.png

image.png

第 2 步——在 user.php:184 设置断点——XSS 发生的位置:

在函数 wp_authenticate_username_password() 内的 return new WP_Error(...) 处设置断点。当调试器暂停时,观察:

  • 面板 Variables → Locals:$username = ""——完整的 HTML 载荷,未转义
  • 面板 Superglobals → $_POST:log = ""——确认载荷源自表单输入
  • 面板 Call Stack:wp_authenticate_username_password() → WP_Hook->apply_filters → apply_filters → wp_authenticate → wp_signon → {main} wp-login.php

image.png

$username 的值从 $_POST['log'] → wp_unslash() →(绕过 sanitize_user)→ 通过 sprintf() 进入第 186-189 行的错误消息——中间没有任何 esc_html()。在实验室中,sanitize_user() 被注释掉,以模拟 pwn.ai 发现的绕过方式。

第 3 步——在 functions.php:9200 设置断点——最终输出:

在 echo wp_get_admin_notice( $message, $args ) 处设置断点——这是 HTML 输出到浏览器之前的最后一行:

  • 面板 Variables → Locals:$message = "<p><strong>Error:</strong> The username <strong></strong> is not registered...</p>"——载荷完整地存在于 HTML 错误消息中
  • 实验室中的第 9200 行没有 wp_kses_post() 包裹(已注释以模拟绕过),因此载荷直接进入浏览器

image.png

在原始 WordPress 中,这一行是 echo wp_kses_post( wp_get_admin_notice(...) )——wp_kses_post() 会剥离 onerror 属性,但会允许 <div id="wp-emoji-settings"> 通过,因为 <div> 在白名单中。这正是 DOM clobbering 攻击的精准向量。

第 4 步:第二个修复提交——加固 emoji-loader

提交 a12c8f5 修改了 emoji-loader.js 以阻止 DOM clobbering:

// BEFORE (vulnerable): accepts any element with a matching id
const settings = JSON.parse(
    document.getElementById('wp-emoji-settings').textContent
);

// AFTER (fixed): only accepts <script> element
const selector = 'script#wp-emoji-settings';
const script = document.querySelector(selector);
if (!(script instanceof HTMLScriptElement)) {
    throw new Error(`Element missing:${selector}`);
}
const settings = JSON.parse(script.text);

此修复更改了 3 处:

  1. 使用 querySelector('script#...') 代替 getElementById——只匹配 <script> 标签
  2. 检查 instanceof HTMLScriptElement——防止通过 <div> 或 `` 进行 DOM clobbering
  3. 使用 .text 代替 .textContent——.text 是 HTMLScriptElement 的特定属性

修复后,即使攻击者设法注入 <div id="wp-emoji-settings">,emoji-loader 也会忽略它,因为它不是 <script> 元素。

4. 攻击链——XSS2Shell

下载工具