JSON Web Token

Liste des différentes attaques sur les JWT

Signature non vérifiée

Principe : Modifier le token puis rejouer la requête en enlevant la partie signature.

Exemple d’un token envoyé sans signature :

eyJraWQiOiIxY2UyYmViZS1hNWIzLTQ2MzgtYWM1MC0yMjM1MjkyYjBkZjQiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY4NjA2MTExN30.

Il est important de garder le séparateur final “.” pour indiquer que la signature est vide.

Explication de la vulnérabilité : certaines librairies fournissent les méthodes verify(), permettant de vérifier une signature, et decode() qui décode simplement le token. L’emploi de ce dernier ne vérifie ainsi pas la signature et est à l’origine de cette vulnérabilité.

Algorithme défini à none

Principe : Modifier l’en-tête alg et mettre sa valeur à none, puis rejouer la requête en enlevant la partie signature.

{
  "alg": "none",
}

Cryptographie avec secret faible

Principe : Récupérer un token JWT et effectuer une attaque par bruteforce ou dictionnaire afin d’en récupérer le secret. Cette méthode ne fonctionne qu’avec des algorithmes de signature symétriques : HS256, HS384 ou HS512).

hashcat -m 16500 -a 3 jwt-token.txt # Bruteforce
hashcat -m 16500 -a 0 jwt-token.txt <WORDLIST> # Attaque par dictionnaire

Injection d’en-tête

Si seul l’attribut alg est obligatoire dans l’en-tête d’un JWT, il existe d’autres attributs optionnels pouvant être manipulés par l’utilisateur. Certains serveurs mal configurés utilisent n’importe quelle clé intégrée dans le paramètre jwt pour vérifier la signature du token. Ces attaques visent alors principalement à remplacer les clés privée/publique du serveur par une paire de clés que l’on contrôle, afin de signer les tokens JWT. Pour générer des clés RSA, il est recommandé d’utiliser l’extension Burp JWT Editor.

JSON Web Key (JWK)

Attribut : Correspond à la clé publique lié à la clé privée servant à signer les JWT. Avec cet attribut, la clé publique est directement injectée dans l’en-tête.

Principe : Signer un token JWT modifié avec sa propre clé privée RSA, puis injecter la clé publique dans l’attribut jwk afin que le token soit vérifié par l’application.

État initial :

{
    "kid": "a04d5d90-ea09-43ec-ad98-22b65c130204",
    "alg": "RS256"
}

En-tête modifiée :

{
    "kid": "d67abaf6-c903-4e87-a4ca-72a5c1e2be3c",
    "alg": "RS256",
    "jwk": {
        "kty": "RSA",
        "e": "AQAB",
        "kid": "d67abaf6-c903-4e87-a4ca-72a5c1e2be3c",
        "n": "mcNhtng1jfZDsvpuC-iWjMllESaMKbkHqfJgxkmIymo6RPBA2E0UayyYjceJnJsmx7lUCz-xUkb2diYuWB5R32NkyJ0nxJ3oMw97S1KKyj3iIZfO92darK83DHGM-q8SYBj40yVgkVP5vd2e5Jq_jGVEZLpLQS4G6vLJMnuggEWnwMZ5KTUpPx36rzKDKp3w3FWTZTZGLE4RhzkR2ZwCKNQQnXD02TEtrENEGBXR21Px5yX-eQ76U7J9yu9bdToWWoYigBufcRywfeU6hhdScXgiK-Xs-1Zkh51JUMSegbv3q1Td0Pqsb5DuRWAtsIBQW8SiE3tIhym5BtfAnEX3Zw"
    }
}

Reproduire avec BurpSuite :

  1. Installer les extensions JSON Web Token et JWT Editor Key ;
  2. Se rendre dans l’onglet JWT Editor Key et générer une nouvelle clé RSA ;
  3. Envoyer une requête contenant un token JWT au Repeater ;
  4. Dans le Repeater, passer sur l’onglet JSON Web Token et modifier le payload du token comme souhaité ;
  5. Cliquer sur “Attack”, puis sélectionner “Embedded JWK” et sélectionner la clé RSA que l’on a généré précédemment ;
  6. Envoyer la requête et regarder le résultat.

JSON Web Key Set URL (JKU)

Attribut : Correspond à un JWT Set contenant des URLs vers des clés publiques. Lors de la vérification d’une signature, le serveur va utiliser les clés présentes sur ces URLs.

Principe : Faire pointer l’URL sur un serveur que l’on possède, et héberger notre propre clé publique pour vérifier le token. Signer le token modifié avec notre clé privée et rejouer les requêtes.

Voici le modèle du fichier jwks.json qui sera hébergé sur notre serveur.

{
    "keys": [
        {
            "kty": "RSA",
            "e": "AQAB",
            "kid": "d67abaf6-c903-4e87-a4ca-72a5c1e2be3c",
            "n": "mcNhtng1jfZDsvpuC-iWjMllESaMKbkHqfJgxkmIymo6RPBA2E0UayyYjceJnJsmx7lUCz-xUkb2diYuWB5R32NkyJ0nxJ3oMw97S1KKyj3iIZfO92darK83DHGM-q8SYBj40yVgkVP5vd2e5Jq_jGVEZLpLQS4G6vLJMnuggEWnwMZ5KTUpPx36rzKDKp3w3FWTZTZGLE4RhzkR2ZwCKNQQnXD02TEtrENEGBXR21Px5yX-eQ76U7J9yu9bdToWWoYigBufcRywfeU6hhdScXgiK-Xs-1Zkh51JUMSegbv3q1Td0Pqsb5DuRWAtsIBQW8SiE3tIhym5BtfAnEX3Zw"
        }
    ]
}

La valeur kid doit être remplacée par celle de l’en-tête du JWT original.

Voici maintenant l’en-tête modifiée avec le paramètre jku pointant vers notre serveur :

{
   "kid": "d67abaf6-c903-4e87-a4ca-72a5c1e2be3c",
   "alg": "RS256",
   "jku": "https://server.fr/jwks.json"
}

Reproduire avec BurpSuite :

  1. Installer les extensions JSON Web Token et JWT Editor Key ;
  2. Se rendre dans l’onglet JWT Editor Key et générer une nouvelle clé RSA ;
  3. Créer un fichier jwks.json à partir du modèle plus haut. Remplacer le kid par celui présent dans l’en-tête original du JWT et le n par celui de la clé publique générée précédemment.
  4. Envoyer une requête contenant un token JWT au Repeater ;
  5. Dans le Repeater, passer sur l’onglet JSON Web Token et modifier le payload du token comme souhaité. Ensuite, rajouter l’attribut jku dans l’en-tête, et mettre l’URL pointant vers le fichier jwks.json en valeur ;
  6. Toujours dans Repeater, dans l’onglet JSON Web Token, cliquer sur Sign en bas de la fenêtre. Sélectionner la clé privée générée et cliquer sur OK. Il est maintenant possible de copier le Serialized JWT et le réutiliser.

Injection dans le paramètre kid

Attribut : Correspond à l’identifiant d’une clé (Key ID).

Principe : Exploiter un path traversal dans la valeur du kid pour le faire pointer vers un fichier local du serveur, puis signer le token JWT modifié avec le secret correspondant au contenu de ce fichier. Ne fonctionne qu’avec un algorithme symétrique (HS***)

Reproduire avec BurpSuite :

  1. Installer les extensions JSON Web Token et JWT Editor Key ;
  2. Se rendre dans l’onglet JWT Editor Key et générer une nouvelle clé symétrique. Dans le cas où le serveur est un Linux, le fichier arbitraire utilisé sera le /dev/null par soucis de simplicité. Remplacer alors la valeur de k par un null-byte (AA==) et sauvegarder la clé ;
  3. Envoyer une requête contenant un token JWT au Repeater ;
  4. Dans le Repeater, passer sur l’onglet JSON Web Token et modifier le payload du token comme souhaité ;
  5. Modifier la valeur du kid en la faisant pointer vers ../../../../../../dev/null ;
  6. Signer le token en cliquant sur Sign et en utilisant la clé symétrique générée précédemment. Il est maintenant possible de copier le Serialized JWT et le réutiliser.

Explication de la vulnérabilité : le kid possède une valeur arbitraire voulue par le développeur. Il peut alors pointer sur une entrée de base de données ou un fichier. Ainsi, si ce paramètre est vulnérable à un path traversal, l’attaquant peut forcer le serveur à utiliser un fichier local prédictible.

Algorithm confusion attacks

Principe : Modifier l’algorithme RSA utilisé par une variante HMAC (HS256/HS384/HS512) et signer le token à l’aide de la clé publique. Ainsi il est ainsi possible de tromper le serveur dans sa fonction de vérification.

Reproduire avec BurpSuite :

  1. Installer les extensions JSON Web Token et JWT Editor Key ;
  2. Récupérer la clé publique en interrogeant des endpoints par défaut (/.well_known/jwks.json ou juste /jwks.json). Copier le contenu présent dans le key ;
  3. Dans BurpSuite, onglet JWT Editor Key, créer une nouvelle clé RSA au format JWT. Coller le contenu de key pour remplacer la valeur générée lors de la création de la clé.
  4. Envoyer une requête contenant un token JWT au Repeater ;
  5. Dans le Repeater, passer sur l’onglet JSON Web Token et modifier le payload du token comme souhaité ;
  6. Cliquer sur Attack, puis sélectionner HMAC Key Confusion. Sélectionner la clé correspondante et cliquer sur OK. Il est maintenant possible de copier le Serialized JWT et le réutiliser.