
CVE-2026-8206: Kirki Customizer Framework – Nicht authentifizierte Kontokompromittierung (CVSS 9.8)
CVSS v3.1 9.8 / 10.0 KRITISCH
Vektor: AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CVE-2026-8206 ist eine Schwachstelle zur nicht authentifizierten Kontoübernahme im Kirki Customizer Framework – einem beliebten WordPress-Pagebuilder-Plugin mit über 90.000 aktiven Installationen. Die Schwachstelle ermöglicht es einem Angreifer, durch das Senden einer einzigen HTTP-Anfrage jedes WordPress-Konto (einschließlich Admin) zu übernehmen.
Der Fehler befindet sich im REST-API-Endpunkt kirki-forgot-password des ComponentLibrary-Moduls. Dieser Endpunkt erlaubt es, für jeden Benutzer ein Passwort-Reset anzufordern, und sendet den Reset-Link an eine vom Angreifer angegebene E-Mail-Adresse, statt an die registrierte E-Mail-Adresse des Benutzers.
| Information | Details |
|---|---|
| Plugin | Kirki Customizer Framework (WordPress Page Builder) |
| Betroffene Versionen | 6.0.0 – 6.0.6 |
| Behoben in | 6.0.7 (oder 6.0.12+) |
| Schwachstellenart | Nicht authentifizierte Kontoübernahme per Hijacking der Passwort-Reset-E-Mail |
| Endpunkt | /index.php?rest_route=/KirkiComponentLibrary/v1/kirki-forgot-password (oder /wp-json/KirkiComponentLibrary/v1/kirki-forgot-password) |
| CVSS | 9.8 KRITISCH |
Voraussetzungen für die Ausnutzung:
→ Jede WordPress-Website mit installiertem Kirki 6.0.0–6.0.6 ist standardmäßig verwundbar.
Kirki registriert REST-API-Endpunkte für die Component-Library-Funktion, einschließlich Login, Register, forgot-password und change-password. Alle erlauben Gastzugriff (guest_permissions_check gibt true zurück).
Ein WordPress-Nonce ist ein CSRF-Schutz-Token. Kirki erfordert ein Nonce über den X-WP-Element-Nonce-Header oder prüft einen Nonce-Parameter in der Anfrage. Das Nonce kann jedoch öffentlich clientseitig generiert/extrahiert werden.
WordPress verwendet get_password_reset_key(), um einen Passwort-Reset-Token zu generieren. Dieser Token wird von Kirki vor dem Senden in die E-Mail-Vorlage eingefügt.
Datei: ComponentLibrary/controller/CompLibFormHandler.php
In der verwundbaren Version (6.0.0–6.0.6) prüft die Funktion handle_forgot_password() nicht, ob die angegebene E-Mail-Adresse mit der registrierten E-Mail-Adresse des Benutzers übereinstimmt. Ein Angreifer kann den Benutzernamen des Opfers und seine eigene E-Mail-Adresse angeben – der Reset-Link wird an die E-Mail-Adresse des Angreifers gesendet.
Verwundbarer Quellcode:
public function handle_forgot_password( $request ) {
$form_data = $request->get_body_params();
$this->validate_nonce( 'kirki-forgot-password' );
$email = $form_data['email']; // <-- ATTACKER CONTROLLED
$username = $form_data['username'];
$user = get_user_by( 'login', $username );
//BUG: Does NOT check $email === $user->user_email
// Attacker's email is used directly
$key = get_password_reset_key( $user );
$reset_link = "$url?action=rp&key=$key&login=$username";
// SENDS RESET LINK TO ATTACKER'S EMAIL
wp_mail( $email, $subject, $body_with_reset_link );
// ^^^^^
// ATTACKER'S EMAIL, NOT THE USER'S EMAIL
}
Der E-Mail-Betreff und der E-Mail-Inhalt werden über die Parameter emailSubject und emailBody vom Client empfangen, ohne dass eine HMAC-Signatur die Integrität absichert. Der Angreifer kann den Inhalt der gesendeten E-Mail beliebig verändern.
// VULNERABLE VERSION: No HMAC verification
$email_subject = $form_data['emailSubject']; // Client-controlled
$email_body = $form_data['emailBody']; // Client-controlled
// No verify_email_template_signature()
// PATCHED VERSION (6.0.7+): HMAC verification / Email matching against DB
$user_email = $user->get( 'user_email' );
if ( $email !== $user_email ) {
return new WP_REST_Response( array( 'message' => 'If an account exists...' ), 200 );
}
| Faktor | Erklärung |
|---|---|
| Keine Authentifizierung erforderlich | guest_permissions_check() gibt true zurück – jeder kann den Endpunkt aufrufen |
| Jedes Konto kann übernommen werden | Nur der Benutzername wird benötigt (Standard: 'admin') – keine E-Mail/Passwort erforderlich |
| Auswirkung: Admin-Übernahme | Admin übernehmen → Webshell hochladen → RCE → volle Serverkontrolle |
| Weit verbreitet | Kirki ist ein Plugin, das in viele WordPress-Themes integriert ist |
Die Ausnutzung von CVE-2026-8206 beginnt ohne jeglichen Zugriff – kein Konto, kein Passwort, keine Sitzung – und führt allein mit HTTP-Anfragen zur vollständigen Admin-Übernahme.
Phase 1: Extract Nonce → Obtain nonce from a public page (if required)
Phase 2: Hijack Reset Email → Send reset link to attacker's email
Phase 3: Reset Password → Change admin password using the obtained reset key
Phase 4: Login Admin → Log in with the new password
Phase 5: Webshell Upload → Install backdoor via plugin upload
Phase 6: RCE → Execute arbitrary commands on the server
Laden Sie das Plugin von wordpress.org herunter und öffnen Sie die Datei CompLibFormHandler.php direkt:
// The handle_forgot_password function receives data from the client:
$email_subject = isset( $form_data['emailSubject'] )
? sanitize_text_field( $form_data['emailSubject'] ) : '';
$email_body = isset( $form_data['emailBody'] )
? json_decode( $form_data['emailBody'], true ) : '';
// Email body rendering logic:
foreach ( $email_body as $body_data ) {
if ( $body_data['type'] === 'text' ) {
$email_body = $email_body . $body_data['value'];
} elseif ( $body_data['type'] === 'chip' ) {
$email_body = $email_body . $chip_data[ $body_data['value'] ];
// ^^^^^^^^^^^^^^^^^^^
// $chip_data['reset_link'] = actual reset URL!
}
}
→ Aus dem Code geht hervor: emailBody muss ein JSON-Array sein, wobei jedes Element type und value besitzt. Wenn type = chip und value = reset_link ist, fügt Kirki den Reset-Link automatisch in die E-Mail ein.
Führen Sie grep direkt im Plugin-Verzeichnis aus:
grep -r "emailBody" wp-content/plugins/kirki/assets/js/
grep -r "reset_link" wp-content/plugins/kirki/assets/js/
Der kompilierte Frontend-Code zeigt die genaue erforderliche JSON-Struktur.
Find endpoint (/wp-json/ or rest_route)
↓
Read PHP source → find $form_data['emailBody']
↓
Understand JSON array format (type / value)
↓
Read chip_data array → find key "reset_link"
↓
Build payload: emailBody=[{"type":"chip","value":"reset_link"}]
↓
Test → success
Der Angreifer sendet eine POST-Anfrage an den Forgot-Password-Endpunkt mit dem Benutzernamen des Opfers (admin) und einer vom Angreifer kontrollierten E-Mail-Adresse ([email protected]). Der Server generiert einen Reset-Schlüssel für das Opfer, sendet den Reset-Link jedoch an [email protected].
Senden der Anfrage: