
Exploit PoC et analyse de la cause racine d'une injection d'objet PHP non authentifiée critique dans WordPress Database for Contact Form 7, menant à une exécution de code à distance (RCE) via la suppression arbitraire de fichiers.
Plugin : Database for Contact Form 7 (contact-form-entries) ≤ 1.4.3
CVSS : 9.8 (Critique)
CWE : CWE-502 — Désérialisation de données non fiables
Exigence d'authentification : Aucune (non authentifié)
Impact : Exécution de code à distance
Le plugin « Database for Contact Form 7 » (slug : contact-form-entries) version 1.4.3 et inférieures contient une vulnérabilité d'injection d'objets PHP. Lorsqu'un administrateur WordPress consulte un enregistrement de formulaire (entrée) dans le panneau d'administration, le plugin appelle la fonction maybe_unserialize() directement sur des données soumises par un utilisateur non authentifié via Contact Form 7, sans contrôler la liste des classes autorisées à être instanciées.
Un attaquant n'a pas besoin de se connecter — il lui suffit de soumettre un formulaire de contact classique en insérant un objet PHP sérialisé dans n'importe quel champ du formulaire. Ces données sont stockées brutes dans la base de données. Lorsqu'un administrateur ouvre l'entrée pour la consulter, la fonction de désérialisation instancie un objet choisi par l'attaquant, déclenchant des méthodes magiques comme __destruct() ou __wakeup() → exécution d'un comportement arbitraire selon les gadgets POP disponibles dans l'environnement WordPress.
Niveau de gravité : Avec un gadget POP approprié (par exemple, une classe dont la méthode
__destruct()appelleunlink()), un attaquant peut supprimer le fichierwp-config.php, ramenant WordPress à son écran d'installation initial → réinstallation avec un compte administrateur contrôlé par l'attaquant → installation d'un plugin contenant une webshell → obtention d'une exécution de code à distance (RCE) complète sur le serveur.
| Attribut | Valeur |
|---|---|
| Identifiant CVE | CVE-2025-7384 |
| Score CVSS | 9.8 (Critique) |
| CWE | CWE-502 — Désérialisation de données non fiables |
| Plugin concerné | contact-form-entries (Database for Contact Form 7) ≤ 1.4.3 |
| Exigence d'authentification | Aucune — toute personne soumettant un formulaire CF7 peut injecter la charge utile |
| Condition de déclenchement | L'administrateur consulte l'entrée injectée dans le panneau d'administration |
| Impact maximal | Exécution de code à distance non authentifiée |
| Version corrigée | 1.4.4+ (remplace unserialize par json_decode ou allowed_classes: false) |
PHP utilise serialize() pour convertir un objet en une chaîne de texte structurée, et unserialize() pour restaurer l'objet à partir de cette chaîne. Lorsque unserialize() reçoit des données provenant d'une source non fiable (par exemple, une entrée utilisateur), un attaquant peut construire un objet arbitraire appartenant à n'importe quelle classe actuellement chargée en mémoire PHP à ce moment-là.
Méthodes spéciales que PHP invoque automatiquement durant le cycle de vie d'un objet. Les plus importantes dans ce contexte :
__wakeup() — invoquée immédiatement lorsqu'un objet est désérialisé__destruct() — invoquée lorsqu'un objet est détruit (sort de la portée, ou la requête se termine)__toString() — invoquée lorsqu'un objet est converti en chaîne de caractèresUne technique consistant à enchaîner plusieurs méthodes magiques de classes existantes dans l'application pour construire une séquence dangereuse de comportements. L'attaquant n'écrit pas de nouveau code — il ne manipule que les propriétés d'objets existants afin que, lorsque les méthodes magiques s'exécutent, elles effectuent des actions non voulues par les développeurs.
maybe_unserialize() dans WordPressUne fonction d'encapsulation (wrapper) du noyau WordPress. Elle appelle is_serialized() pour vérifier si une chaîne est des données sérialisées — si c'est le cas, elle appelle unserialize() pour restaurer l'objet. Problème : cette fonction ne passe pas le paramètre allowed_classes (disponible depuis PHP 7.0) pour limiter les classes autorisées à l'instanciation.
Commencez par parcourir l'ensemble du code source du plugin avec grep pour localiser les fonctions de désérialisation — ce sont les fonctions les plus dangereuses en PHP car elles peuvent mener à une injection d'objets :
grep -rn "unserialize" wp-src/wp-content/plugins/contact-form-entries/

La sortie révèle plusieurs points d'appel de maybe_unserialize(), notamment dans includes/data.php à la ligne 545 au sein de la fonction 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;
}
Question clé : D'où provient la variable $string ? Si elle provient d'une entrée utilisateur sans filtrage → c'est une vulnérabilité.
Trouvez où verify_val() est appelée. Tracez en arrière dans le même fichier data.php :

// 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 correspond exactement à $v['value'] — les valeurs extraites de la table wp_vxcf_leads_detail. Cette fonction est appelée lorsqu'un administrateur consulte les détails d'une entrée de formulaire.
Question suivante : D'où proviennent les données dans wp_vxcf_leads_detail ? Qui les écrit ?
D'après l'étape 2, les données sont lues depuis la base de données. Question suivante : qui y écrit des données ? Recherchez les requêtes INSERT dans data.php :
grep -rn "insert" wp-src/wp-content/plugins/contact-form-entries/includes/data.php

Ouvrez le code de la fonction create_lead() (lignes 85-103) pour plus de détails :