Contournement d’authentification JWT par confusion d’algorithme (clé publique non exposée)

JWT authentication bypass via algorithm confusion with no exposed key

Contexte du lab

Nous utilisons des JWT pour gérer la session. Les jetons sont normalement signés en RSA (RS256) avec une paire de clés robuste :

  • clé privée : signer les JWT

  • clé publique : vérifier les JWT

La faiblesse vient d’une implémentation incorrecte : le serveur accepte un JWT déclaré en HS256 et réutilise (à tort) la clé publique RSA comme secret HMAC.

Objectif : obtenir un JWT valide avec sub=administrator, accéder à /admin, puis supprimer carlos.

Récupération de deux JWT RS256

Nous nous connectons avec wiener:peter et nous récupérons un premier JWT RS256 :

TOKEN 1

Ensuite, nous nous déconnectons puis nous nous reconnectons afin d’obtenir un second JWT RS256 (même kid, signature différente) :

TOKEN 2

Reconstruction d’une clé publique RSA valide avec sig2n

Nous utilisons l’outil sig2n (PortSwigger) dans Docker pour reconstruire une clé publique à partir de TOKEN 1 et TOKEN 2 :

Avec nos deux tokens complets :

L’outil renvoie notamment :

  • Base64 encoded x509 key (clé publique)

  • Tampered JWT (JWT HS256 de test)

Dans notre cas, la clé x509 renvoyée est :

Test : validation d’un JWT HS256 “tampered”

Nous testons le JWT HS256 fourni par sig2n :

Le serveur l’accepte

Donc la clé publique reconstruite est utilisable comme secret HMAC.

Création d’une clé symétrique (oct) avec la clé publique

Nous créons une clé symétrique de type oct dont la valeur k est la clé publique base64 :

Forge du JWT administrateur

Payload (on passe en administrator)

Header (on bascule en HS256 et on conserve le kid attendu)

Nous signons ensuite ce JWT en HS256 avec la clé symétrique créée (secret = clé publique).

Exploitation

  1. Nous remplaçons le cookie JWT par notre jeton HS256 forgé.

  2. Nous allons sur /admin.

  3. Nous supprimons l’utilisateur carlos.

Mis à jour