1. Descripción técnica
Un Weak JWT Secret aparece cuando una aplicación firma JSON Web Tokens con un algoritmo HMAC, como HS256, pero utiliza una clave con poca entropía: por ejemplo, una contraseña, una palabra de diccionario, un valor por defecto o una cadena predecible.
El problema no es HS256 por sí mismo. HMAC-SHA-256 puede proporcionar una firma robusta cuando recibe una clave secreta generada aleatoriamente y con tamaño suficiente. La debilidad aparece cuando el espacio de claves que debe probar un atacante es pequeño en la práctica.
El límite de confianza separa al cliente, que puede leer y reenviar el token, del servidor, que debe decidir si ese token procede de un emisor autorizado. Cuando el secreto puede recuperarse, el atacante adquiere la capacidad criptográfica del emisor: puede construir datos nuevos y acompañarlos de una firma que el verificador considera válida.
1.1. Estructura de un JWT firmado
En su representación compacta, un JWT firmado como JWS suele contener tres segmentos separados por puntos:
base64url(header).base64url(payload).base64url(signature)| Segmento | Contenido | Propósito |
|---|---|---|
| Header | Metadatos como alg: HS256 y typ: JWT | Indica cómo debe procesarse el token |
| Payload | Claims como identidad, rol, emisor o expiración | Transporta las afirmaciones que consumirá la aplicación |
| Signature | Resultado criptográfico calculado sobre los dos primeros segmentos | Permite detectar modificaciones y autenticar al emisor que conoce la clave |
Un claim es una afirmación contenida en el payload. sub puede identificar al sujeto, exp marca una expiración y una aplicación puede añadir claims propios como role.
Base64url es una codificación, no un cifrado. Cualquiera que posea el token puede decodificar normalmente el header y el payload. La confidencialidad requeriría un JWT cifrado mediante JWE u otra protección; una firma JWS protege integridad y autenticidad, no oculta los claims. RFC 7519.
1.2. Lectura de un JWT literal
Este es el token que la aplicación entrega al usuario pwned en 035-aurora. Un JWT compacto debe copiarse como una sola línea:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InB3bmVkIiwicm9sZSI6InVzZXIiLCJpYXQiOjE3MDk1MTk5MzR9.qYFPMbLujQYh1d24oYjTwmwwYPXM_jJdAdSDCq6GPmILos dos caracteres . separan sus tres segmentos:
Header: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
Payload: eyJ1c2VybmFtZSI6InB3bmVkIiwicm9sZSI6InVzZXIiLCJpYXQiOjE3MDk1MTk5MzR9
Signature: qYFPMbLujQYh1d24oYjTwmwwYPXM_jJdAdSDCq6GPmIAl decodificar Base64url, el header contiene:
{
"alg": "HS256",
"typ": "JWT"
}El payload contiene:
{
"username": "pwned",
"role": "user",
"iat": 1709519934
}alg declara el algoritmo de firma, typ identifica el tipo de objeto e iat registra el instante de emisión como tiempo Unix. El claim role es propio de la aplicación y representa el dato que después influye en la autorización.
La firma no se convierte en un objeto JSON legible. Es el resultado binario de HMAC-SHA-256 representado en Base64url. Decodificar los dos primeros segmentos permite inspeccionar el token, pero todavía no prueba que la firma sea válida ni que el servidor confíe en sus claims.
1.3. Cómo firma y verifica HS256
HS256 utiliza HMAC con SHA-256. HMAC combina un mensaje con una clave secreta para producir un código de autenticación. En un JWS compacto, el mensaje firmado es exactamente la unión del header codificado, un punto y el payload codificado:
signing_input = base64url(header) + "." + base64url(payload)
signature = HMAC-SHA-256(secret, signing_input)El emisor calcula esa firma al crear el token. El servidor verificador repite el cálculo con el mismo secreto y compara ambos resultados. Si coinciden, puede concluir que el contenido no cambió desde que lo firmó alguien que conocía la clave. RFC 7515, JWS, RFC 7518, HMAC con SHA-2.
HMAC es simétrico: la misma clave permite firmar y verificar. Por ello, todo componente que pueda verificar tokens HS256 con el secreto también tiene material suficiente para crear tokens válidos. Esto amplía el impacto de una filtración o reutilización de la clave.
1.4. Por qué la clave puede probarse fuera de línea
Un token válido entrega al atacante todo lo necesario para comprobar candidatos:
- El header y el payload proporcionan el mensaje exacto que fue firmado.
- El tercer segmento proporciona la firma HMAC esperada.
- Para cada clave candidata se vuelve a calcular HMAC sobre el mismo mensaje.
- Si el resultado coincide con la firma observada, se ha encontrado una clave compatible con el token.
La comprobación es determinista y no requiere enviar cada intento al servidor. Por eso es un ataque fuera de línea: los límites de peticiones, bloqueos de cuenta y CAPTCHA del endpoint de inicio de sesión no reducen directamente su velocidad. La defensa principal es que la clave tenga suficiente entropía para que recorrer su espacio resulte impracticable.
// renderizando diagrama…
Una contraseña larga no equivale necesariamente a una clave fuerte: si procede de lenguaje humano o de un patrón conocido, su entropía puede seguir siendo baja. Para HS256, RFC 7518 exige claves de al menos 256 bits, y RFC 8725 prohíbe usar directamente contraseñas memorizables como claves de algoritmos MAC. RFC 8725, secciones 2.2 y 3.5.
2. Impacto y límites
Con el secreto correcto, un atacante puede modificar claims y generar la firma correspondiente. El impacto depende de las decisiones que la aplicación base en esos claims:
| Claim o uso confiado | Consecuencia posible |
|---|---|
Identidad, como sub o username | Suplantación de otro usuario |
Rol o permisos, como role o scope | Escalada de privilegios o bypass de autorización |
| Emisor o audiencia sin validación adecuada | Uso del token en un servicio o contexto distinto |
| Claims de negocio | Manipulación de operaciones que confían en esos valores |
Si varios servicios o entornos comparten el secreto, una sola recuperación puede permitir falsificar tokens aceptados por todos ellos. El alcance debe analizarse por emisor, audiencia, entorno y recurso verificador.
Recuperar la clave no revela contraseñas de usuarios ni descifra información por sí mismo. Tampoco demuestra ejecución de comandos. La RCE sólo aparece si el token falsificado abre acceso a otra funcionalidad vulnerable, como ocurre con OS Command Injection en 035-aurora.
3. Condiciones necesarias
- El atacante obtiene al menos un JWT válido firmado como JWS con un algoritmo HMAC, por ejemplo HS256, HS384 o HS512.
- La clave pertenece a un espacio de búsqueda práctico debido a baja entropía, reutilización, un valor por defecto o información previa.
- El servidor sigue verificando tokens con esa clave y acepta el algoritmo utilizado.
- El atacante puede presentar un token nuevo al componente verificador.
- Para producir un efecto de autorización, la aplicación debe confiar en claims que el atacante pueda modificar.
Observar alg: HS256 no prueba la vulnerabilidad. Tampoco la prueba el simple hecho de decodificar el payload: ambas situaciones son normales en un JWT firmado. La exposición se confirma cuando una clave candidata reproduce la firma y, para validar el impacto operativo, el servidor acepta un token de prueba firmado con ella.
4. Validación y detección
4.1. Qué demuestra cada comprobación
| Evidencia | Interpretación correcta |
|---|---|
| Header y payload legibles | El token no oculta esos datos; no demuestra una clave débil |
| Payload modificado y rechazado | La verificación de firma detectó el cambio; es el comportamiento esperado |
| Una clave candidata reproduce localmente la firma | La clave es compatible con ese token firmado |
| Un token nuevo firmado con esa clave es aceptado | La aplicación acepta falsificaciones con la configuración activa |
| Un claim privilegiado cambia la respuesta autorizada | La falsificación afecta una decisión de acceso concreta |
En una evaluación autorizada, conviene separar la prueba criptográfica de la prueba de impacto. Primero se verifica localmente la firma del token conocido. Después se utiliza un token de prueba con el cambio mínimo necesario para confirmar que el servidor consume la firma y el claim investigado.
La guía de OWASP describe la búsqueda de claves HMAC débiles mediante diccionarios y herramientas capaces de comprobar candidatos contra un JWT conocido. OWASP WSTG, Weak HMAC Keys.
4.2. Revisión defensiva
La revisión del código, la configuración y el gestor de secretos debe buscar:
- contraseñas o frases utilizadas directamente como claves HMAC;
- valores de ejemplo o secretos por defecto que llegaron al despliegue;
- claves incluidas en repositorios, imágenes o archivos accesibles;
- reutilización entre aplicaciones, emisores o entornos;
- claves con menos tamaño o entropía de lo requerido por el algoritmo;
- verificadores que no fijan una lista permitida de algoritmos, emisor y audiencia.
Los intentos de diccionario fuera de línea no llegan al servidor y, por tanto, no generan eventos de autenticación. La telemetría sólo puede mostrar el uso posterior: combinaciones de identidad y rol inusuales, tokens empleados desde contextos inesperados o actividad incompatible con el usuario. Una falsificación bien construida es criptográficamente indistinguible de un token legítimo firmado con la misma clave, por lo que la rotación es necesaria ante una recuperación o exposición confirmada.
5. Explotación documentada en los writeups
5.1. 035-aurora
La aplicación entrega un JWT cuyo header indica HS256 y cuyo payload contiene username: pwned y role: user. John prueba claves candidatas contra la firma conocida y recupera nopassword.
El token literal y su contenido decodificado se muestran en la sección 1.2. Para comprender qué debe cambiar, podemos unir el header original, el nuevo payload administrativo y la firma antigua:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNzA5NTE5OTM0fQ.qYFPMbLujQYh1d24oYjTwmwwYPXM_jJdAdSDCq6GPmIEste es un ejemplo didáctico construido a partir de los segmentos documentados. Es inválido: el payload ya no es el que produjo la firma qYFPM..., por lo que un verificador correcto calcula un HMAC diferente y rechaza el token.
Después de recuperar nopassword, se calcula la firma correspondiente al nuevo header.payload. El token administrativo documentado en el laboratorio es:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNzA5NTE5OTM0fQ.47U7LpOez6J-dRTZPlGWAcz3ZwUTj0K6lAqQFthPK9MSu payload decodificado es:
{
"username": "admin",
"role": "admin",
"iat": 1709519934
}La transformación completa queda visible al comparar los valores:
| Elemento | Token original | Token falsificado |
|---|---|---|
username | pwned | admin |
role | user | admin |
iat | 1709519934 | 1709519934 |
| Firma | qYFPMb...6GPmI | 47U7Lp...hPK9M |
La aplicación acepta la firma nueva y permite acceder a /execute, lo que confirma que confía en el claim role para autorizar el endpoint.
Esta evidencia confirma una clave HMAC débil y la falsificación de un token administrativo. No muestra cómo se almacenaba el secreto, por lo que no permite afirmar que estuviera hard-coded. El acceso obtenido tampoco ejecuta comandos por sí solo: la ejecución posterior depende de una OS Command Injection independiente en el campo command.
6. Mitigación
- Generar la clave con un CSPRNG. Para HS256 debe tener al menos 256 bits de material aleatorio; HS384 y HS512 requieren tamaños mínimos acordes con sus salidas.
- No utilizar contraseñas, nombres de proyecto, cadenas de ejemplo, valores por defecto ni secretos transformados de forma predecible.
- Almacenar la clave en un gestor de secretos y restringir su lectura a los procesos que realmente deban firmar o verificar.
- Separar claves por aplicación, emisor, entorno y propósito para limitar el alcance de una exposición.
- Fijar explícitamente los algoritmos aceptados y validar
iss,aud,exp,nbfy los claims de autorización que correspondan al protocolo. - Rotar inmediatamente una clave expuesta o recuperable, retirar la anterior del conjunto de verificación y revocar o invalidar los tokens emitidos con ella.
- Usar expiraciones breves y un mecanismo de revocación cuando el riesgo de sesiones activas lo requiera.
- Considerar firmas asimétricas cuando varios servicios sólo necesiten verificar. Así, los verificadores reciben una clave pública que no les permite emitir tokens, aunque todavía deben protegerse la clave privada y la validación de claims.
7. Clasificación
- CWE principal: CWE-331: Insufficient Entropy, cuando la clave fue generada o elegida desde un espacio predecible.
- CWE condicional: CWE-321: Use of Hard-coded Cryptographic Key, sólo cuando existe evidencia de que la clave está embebida y no puede cambiarse de forma segura.
- Vector: ataque de diccionario o fuerza bruta fuera de línea contra una firma HMAC conocida.
- Impacto: falsificación de tokens, suplantación de identidad y bypass de autorización según los claims confiados.