
Exploit-PoC und Root-Cause-Analyse für eine kritische, nicht authentifizierte PHP-Objektinjektion in WordPress Database for Contact Form 7, die über beliebiges Löschen von Dateien zu RCE führt.
Plugin: Database for Contact Form 7 (contact-form-entries) ≤ 1.4.3
CVSS: 9.8 (Kritisch)
CWE: CWE-502 — Deserialisierung nicht vertrauenswürdiger Daten
Authentifizierungsanforderung: Keine (nicht authentifiziert)
Auswirkung: Remote Code Execution
Das Plugin „Database for Contact Form 7" (Slug: contact-form-entries) in Version 1.4.3 und früher enthält eine Schwachstelle zur PHP-Objektinjektion. Wenn ein WordPress-Administrator einen Formulardatensatz (Eintrag) im Admin-Panel anzeigt, ruft das Plugin die Funktion maybe_unserialize() direkt mit Daten auf, die ein nicht authentifizierter Benutzer über Contact Form 7 übermittelt hat, ohne die Liste der zulässigen zu instanziierenden Klassen zu kontrollieren.
Ein Angreifer muss sich nicht anmelden — er muss lediglich ein normales Kontaktformular absenden und dabei ein serialisiertes PHP-Objekt in ein beliebiges Formularfeld einfügen. Diese Daten werden unverändert in der Datenbank gespeichert. Wenn ein Administrator den Eintrag zur Ansicht öffnet, instanziiert die Deserialisierungsfunktion ein Objekt nach Wahl des Angreifers und löst damit Magische Methoden wie __destruct() oder __wakeup() aus → abhängig von den im WordPress-Umfeld verfügbaren POP-Gadgets wird beliebiges Verhalten ausgeführt.
Schweregrad: Mit einem geeigneten POP-Gadget (zum Beispiel einer Klasse, deren
__destruct()-Methodeunlink()aufruft), kann ein Angreifer die Dateiwp-config.phplöschen, wodurch WordPress zum anfänglichen Installationsbildschirm zurückkehrt → Neuinstallation mit einem vom Angreifer kontrollierten Administrator-Konto → Installation eines Plugins mit Webshell → vollständige Remote Code Execution (RCE) auf dem Server.
| Attribut | Wert |
|---|---|
| CVE ID | CVE-2025-7384 |
| CVSS-Score | 9.8 (Kritisch) |
| CWE | CWE-502 — Deserialisierung nicht vertrauenswürdiger Daten |
| Betroffenes Plugin | contact-form-entries (Database for Contact Form 7) ≤ 1.4.3 |
| Authentifizierungsanforderung | Keine — jeder, der ein CF7-Formular absendet, kann ein Payload injizieren |
| Auslösebedingung | Administrator betrachtet den injizierten Eintrag im Admin-Panel |
| Maximale Auswirkung | Nicht authentifizierte Remote Code Execution |
| Behobene Version | 1.4.4+ (ersetzt unserialize durch json_decode bzw. allowed_classes: false) |
PHP verwendet serialize(), um ein Objekt in einen strukturierten Textstring zu konvertieren, und unserialize(), um das Objekt aus diesem String wiederherzustellen. Wenn unserialize() Daten aus einer nicht vertrauenswürdigen Quelle (z. B. Benutzereingaben) erhält, kann ein Angreifer ein beliebiges Objekt konstruieren, das zu einer Klasse gehört, die zu diesem Zeitpunkt im PHP-Speicher geladen ist.
Besondere Methoden, die PHP automatisch während des Lebenszyklus eines Objekts aufruft. Am wichtigsten in diesem Zusammenhang:
__wakeup() — wird sofort aufgerufen, wenn ein Objekt deserialisiert wird__destruct() — wird aufgerufen, wenn ein Objekt zerstört wird (den Gültigkeitsbereich verlässt oder die Anfrage endet)__toString() — wird aufgerufen, wenn ein Objekt in einen String umgewandelt wirdEine Technik, bei der mehrere Magische Methoden aus vorhandenen Klassen innerhalb der Anwendung zu einer gefährlichen Abfolge von Verhaltensweisen verkettet werden. Der Angreifer schreibt keinen neuen Code — er manipuliert lediglich die Eigenschaften vorhandener Objekte, sodass bei der Ausführung der Magischen Methoden Aktionen durchgeführt werden, die von den Entwicklern nicht beabsichtigt waren.
maybe_unserialize() in WordPressEine Wrapper-Funktion des WordPress-Kerns. Sie ruft is_serialized() auf, um zu prüfen, ob ein String serialisierte Daten enthält — falls ja, ruft sie unserialize() auf, um das Objekt wiederherzustellen. Problem: Diese Funktion übergibt den Parameter allowed_classes (verfügbar seit PHP 7.0) nicht, um einzuschränken, welche Klassen instanziiert werden dürfen.
Durchsuchen Sie den gesamten Plugin-Quellcode per grep, um Deserialisierungsfunktionen zu lokalisieren — diese gehören zu den gefährlichsten Funktionen in PHP, da sie zu Objektinjektion führen können:
grep -rn "unserialize" wp-src/wp-content/plugins/contact-form-entries/

Die Ausgabe zeigt mehrere Aufrufstellen für maybe_unserialize(), insbesondere in includes/data.php Zeile 545 innerhalb der Funktion verify_val():

// data.php lines 538-548
public function verify_val($string){
if(in_array(substr(ltrim($string),0,1), array('{','['))
&& in_array(substr(rtrim($string),-1), array('}',']'))
){
$val = json_decode($string, 1);
if(is_array($val)){ $string = $val; }
} else if(is_serialized($string)){ // line 544
$string = maybe_unserialize($string); // ★ line 545 — SINK
}
return $string;
}
Kernfrage: Woher stammt die Variable $string? Wenn sie ohne Filterung aus Benutzereingaben stammt → handelt es sich um eine Schwachstelle.
Finden Sie heraus, wo verify_val() aufgerufen wird. Verfolgen Sie die Aufrufe in derselben Datei data.php rückwärts:

// data.php lines 520-535
public function get_lead_detail($lead_id){
global $wpdb;
$table = $wpdb->prefix . 'vxcf_leads_detail';
$detail_arr = $wpdb->get_results(
$wpdb->prepare("SELECT * FROM $table WHERE lead_id=%d", $lead_id),
ARRAY_A
);
foreach($detail_arr as $k => $v){
if(!empty($v['value'])){
$detail_arr[$k]['value'] = $this->verify_val($v['value']); // ← calls verify_val
}
}
return $detail_arr;
}
→ $string ist exakt $v['value'] — Werte, die aus der Datenbanktabelle wp_vxcf_leads_detail abgerufen werden. Diese Funktion wird aufgerufen, wenn ein Administrator die Details eines Formulareintrags anzeigt.
Nächste Frage: Woher stammen die Daten in wp_vxcf_leads_detail? Wer schreibt sie?
Aus Schritt 2 wissen wir, dass Daten aus der Datenbank gelesen werden. Nächste Frage: Wer schreibt Daten hinein? Suchen Sie nach INSERT-Abfragen in data.php:
grep -rn "insert" wp-src/wp-content/plugins/contact-form-entries/includes/data.php

Öffnen Sie den Code der Funktion create_lead() (Zeilen 85–103) für Details:
