JWT Vulnerabilities (Json Web Tokens)
Last updated
Last updated
Si vous êtes intéressé par une carrière en piratage et pirater l'impiratable - nous recrutons ! (maîtrise du polonais écrit et parlé requise).
Une partie de ce post est basée sur le super post : https://github.com/ticarpi/jwt_tool/wiki/Attack-Methodology Auteur de l'excellent outil pour pentester les JWTs https://github.com/ticarpi/jwt_tool
Exécutez jwt_tool en mode Tous les tests !
et attendez les lignes vertes
Si vous avez de la chance, l'outil trouvera un cas où l'application web ne vérifie pas correctement le JWT :
Ensuite, vous pouvez rechercher la requête dans votre proxy ou extraire le JWT utilisé pour cette requête en utilisant l'outil jwt_ :
Vous pouvez simplement manipuler les données en laissant la signature telle quelle et vérifier si le serveur vérifie la signature. Essayez par exemple de changer votre nom d'utilisateur en "admin".
Pour vérifier si la signature d'un JWT est vérifiée :
Un message d'erreur suggère une vérification en cours ; les détails sensibles dans les erreurs verbeuses doivent être examinés.
Un changement dans la page renvoyée indique une vérification.
Aucun changement ne suggère aucune vérification ; c'est le moment d'expérimenter en altérant les revendications de la charge utile.
Il est important de déterminer si le jeton a été généré côté serveur ou côté client en examinant l'historique des requêtes du proxy.
Les jetons d'abord vus côté client suggèrent que la clé pourrait être exposée au code côté client, nécessitant une enquête plus approfondie.
Les jetons d'origine côté serveur indiquent un processus sécurisé.
Vérifiez si le jeton dure plus de 24h... peut-être n'expire-t-il jamais. S'il y a un champ "exp", vérifiez si le serveur le gère correctement.
Définissez l'algorithme utilisé comme "None" et supprimez la partie signature.
Utilisez l'extension Burp appelée "JSON Web Token" pour tester cette vulnérabilité et modifier différentes valeurs à l'intérieur du JWT (envoyez la requête à Repeater et dans l'onglet "JSON Web Token" vous pouvez modifier les valeurs du jeton. Vous pouvez également choisir de mettre la valeur du champ "Alg" à "None").
L'algorithme HS256 utilise la clé secrète pour signer et vérifier chaque message. L'algorithme RS256 utilise la clé privée pour signer le message et utilise la clé publique pour l'authentification.
Si vous changez l'algorithme de RS256 à HS256, le code côté serveur utilise la clé publique comme clé secrète, puis utilise l'algorithme HS256 pour vérifier la signature.
Ensuite, en utilisant la clé publique et en changeant RS256 en HS256, nous pourrions créer une signature valide. Vous pouvez récupérer le certificat du serveur web exécutant ceci :
Un attaquant intègre une nouvelle clé dans l'en-tête du jeton et le serveur utilise cette nouvelle clé pour vérifier la signature (CVE-2018-0114).
Cela peut être fait avec l'extension Burp "JSON Web Tokens". (Envoyez la requête au Repeater, dans l'onglet JSON Web Token sélectionnez "CVE-2018-0114" et envoyez la requête).
Les instructions détaillent une méthode pour évaluer la sécurité des jetons JWT, en particulier ceux utilisant une revendication d'en-tête "jku". Cette revendication devrait être liée à un fichier JWKS (Jeu de clés Web JSON) contenant la clé publique nécessaire à la vérification du jeton.
Évaluation des jetons avec l'en-tête "jku":
Vérifiez l'URL de la revendication "jku" pour vous assurer qu'elle mène au fichier JWKS approprié.
Modifiez la valeur "jku" du jeton pour diriger vers un service web contrôlé, permettant l'observation du trafic.
Surveillance des interactions HTTP:
Observer les requêtes HTTP vers l'URL spécifiée indique les tentatives du serveur pour récupérer les clés à partir du lien fourni.
Lors de l'utilisation de jwt_tool
pour ce processus, il est crucial de mettre à jour le fichier jwtconf.ini
avec l'emplacement de votre JWKS personnel pour faciliter les tests.
Commande pour jwt_tool
:
Exécutez la commande suivante pour simuler le scénario avec jwt_tool
:
Une revendication d'en-tête facultative appelée kid
est utilisée pour identifier une clé spécifique, ce qui devient particulièrement vital dans les environnements où plusieurs clés existent pour la vérification de la signature du jeton. Cette revendication aide à sélectionner la clé appropriée pour vérifier la signature d'un jeton.
Lorsque la revendication kid
est présente dans l'en-tête, il est conseillé de rechercher le répertoire web pour le fichier correspondant ou ses variations. Par exemple, si "kid":"key/12345"
est spécifié, les fichiers /key/12345 et /key/12345.pem doivent être recherchés dans la racine du site web.
La revendication kid
peut également être exploitée pour naviguer à travers le système de fichiers, permettant potentiellement la sélection d'un fichier arbitraire. Il est possible de tester la connectivité ou d'exécuter des attaques de falsification de requête côté serveur (SSRF) en modifiant la valeur kid
pour cibler des fichiers ou des services spécifiques. La manipulation du JWT pour changer la valeur kid
tout en conservant la signature d'origine peut être réalisée en utilisant le drapeau -T
dans jwt_tool, comme démontré ci-dessous:
En ciblant des fichiers avec un contenu prévisible, il est possible de falsifier un JWT valide. Par exemple, le fichier /proc/sys/kernel/randomize_va_space
dans les systèmes Linux, connu pour contenir la valeur 2, peut être utilisé dans le paramètre kid
avec 2 comme mot de passe symétrique pour la génération de JWT.
Si le contenu de la revendication kid
est utilisé pour récupérer un mot de passe depuis une base de données, une injection SQL pourrait être facilitée en modifiant la charge utile kid
. Un exemple de charge utile qui utilise une injection SQL pour modifier le processus de signature JWT est :
non-existent-index' UNION SELECT 'ATTACKER';-- -
Cette modification force l'utilisation d'une clé secrète connue, ATTACKER
, pour la signature JWT.
Un scénario où le paramètre kid
spécifie un chemin de fichier utilisé dans un contexte d'exécution de commande pourrait entraîner des vulnérabilités d'Exécution de Code à Distance (RCE). En injectant des commandes dans le paramètre kid
, il est possible d'exposer des clés privées. Un exemple de charge utile pour atteindre une RCE et l'exposition de clés est :
/root/res/keys/secret7.key; cd /root/res/keys/ && python -m SimpleHTTPServer 1337&
jku signifie URL de jeu de clés JWK. Si le jeton utilise une revendication d'en-tête "jku", vérifiez l'URL fournie. Cela devrait pointer vers une URL contenant le fichier JWKS qui détient la clé publique pour vérifier le jeton. Manipulez le jeton pour pointer la valeur jku vers un service web dont vous pouvez surveiller le trafic.
Tout d'abord, vous devez créer un nouveau certificat avec de nouvelles clés privées et publiques.
Ensuite, vous pouvez utiliser par exemple jwt.io pour créer le nouveau JWT avec les clés publiques et privées créées et en pointant le paramètre jku vers le certificat créé. Pour créer un certificat jku valide, vous pouvez télécharger l'original et modifier les paramètres nécessaires.
Vous pouvez obtenir les paramètres "e" et "n" à partir d'un certificat public en utilisant :
X.509 URL. Un URI pointant vers un ensemble de certificats publics X.509 (un standard de format de certificat) encodés sous forme PEM. Le premier certificat de l'ensemble doit être celui utilisé pour signer ce JWT. Les certificats suivants signent chacun le précédent, complétant ainsi la chaîne de certificats. X.509 est défini dans la RFC 5280. Une sécurité de transport est requise pour transférer les certificats.
Essayez de modifier cet en-tête pour qu'il pointe vers une URL sous votre contrôle et vérifiez si une requête est reçue. Dans ce cas, vous pourriez altérer le JWT.
Pour falsifier un nouveau jeton en utilisant un certificat contrôlé par vous, vous devez créer le certificat et extraire les clés publique et privée :
Ensuite, vous pouvez utiliser par exemple jwt.io pour créer le nouveau JWT avec les clés publiques et privées créées et en pointant le paramètre x5u vers le certificat .crt créé.
Vous pouvez également abuser de ces deux vulnérabilités pour les SSRFs.
Ce paramètre peut contenir le certificat en base64 :
Si l'attaquant génère un certificat auto-signé et crée un jeton falsifié en utilisant la clé privée correspondante et remplace la valeur du paramètre "x5c" par le certificat nouvellement généré et modifie les autres paramètres, à savoir n, e et x5t, alors essentiellement le jeton falsifié serait accepté par le serveur.
Si le JWT contient une clé publique intégrée comme dans le scénario suivant:
En utilisant le script nodejs suivant, il est possible de générer une clé publique à partir de ces données:
Il est possible de générer une nouvelle clé privée/publique, d'incorporer la nouvelle clé publique à l'intérieur du jeton et de l'utiliser pour générer une nouvelle signature :
Vous pouvez obtenir les "n" et "e" en utilisant ce script nodejs :
Si certaines applications utilisent ES256 et utilisent le même nonce pour générer deux JWT, la clé privée peut être récupérée.
Voici un exemple: ECDSA: Révéler la clé privée, si le même nonce est utilisé (avec SECP256k1)
La revendication JTI (JWT ID) fournit un identifiant unique pour un jeton JWT. Il peut être utilisé pour empêcher le jeton d'être rejoué. Cependant, imaginez une situation où la longueur maximale de l'ID est de 4 (0001-9999). Les requêtes 0001 et 10001 vont utiliser le même ID. Donc, si le backend incrémente l'ID à chaque requête, vous pourriez abuser de cela pour rejouer une requête (nécessitant d'envoyer 10000 requêtes entre chaque rejoue réussi).
Attaques de relais entre services
Il a été observé que certaines applications web s'appuient sur un service JWT de confiance pour la génération et la gestion de leurs jetons. Des cas ont été enregistrés où un jeton, généré pour un client par le service JWT, a été accepté par un autre client du même service JWT. Si l'émission ou le renouvellement d'un JWT via un service tiers est observé, la possibilité de s'inscrire à un compte sur un autre client de ce service en utilisant le même nom d'utilisateur/email devrait être investiguée. Une tentative devrait ensuite être faite pour rejouer le jeton obtenu dans une requête vers la cible pour voir s'il est accepté.
Un problème critique peut être indiqué par l'acceptation de votre jeton, permettant potentiellement le spoofing du compte de n'importe quel utilisateur. Cependant, il convient de noter qu'une autorisation pour des tests plus larges pourrait être requise si l'inscription sur une application tierce est nécessaire, car cela pourrait entrer dans une zone grise légale.
Vérification de l'expiration des jetons
L'expiration du jeton est vérifiée en utilisant la revendication Payload "exp". Étant donné que les JWT sont souvent utilisés sans information de session, une manipulation prudente est requise. Dans de nombreux cas, capturer et rejouer le JWT d'un autre utilisateur pourrait permettre l'usurpation de cet utilisateur. La RFC JWT recommande de lutter contre les attaques de rejouement JWT en utilisant la revendication "exp" pour définir une heure d'expiration pour le jeton. De plus, la mise en œuvre de vérifications pertinentes par l'application pour garantir le traitement de cette valeur et le rejet des jetons expirés est crucial. Si le jeton inclut une revendication "exp" et que les limites de temps de test le permettent, il est conseillé de stocker le jeton et de le rejouer après que le délai d'expiration soit passé. Le contenu du jeton, y compris l'analyse de l'horodatage et la vérification de l'expiration (horodatage en UTC), peut être lu en utilisant le drapeau -R de l'outil jwt_tool.
Un risque de sécurité peut être présent si l'application valide toujours le jeton, car cela pourrait impliquer que le jeton ne pourrait jamais expirer.
Si vous êtes intéressé par une carrière en piratage et pirater l'impossible - nous recrutons ! (maîtrise du polonais écrit et parlé requis).