JWT Forgery (Embedded JWK, Weak RSA)
Arsenal completo de comandos en la cheatsheetUn JWT firmado con RS256 se valida con una clave RSA: el servidor firma con la privada y comprueba con la pública. El abuso aparece cuando se juntan dos errores de diseño.
El primero es confiar en la clave que viaja dentro del propio token. Algunas implementaciones meten la clave pública en un campo jwk (dentro de la cabecera o del payload) y validan la firma contra esa clave embebida en lugar de contra una almacenada en el servidor. Si el atacante puede sustituir esa clave, puede firmar lo que quiera: el token se autovalida.
El segundo, y el que remata el caso, es un módulo RSA factorizable. La seguridad de RSA se apoya en que n = p·q no se puede factorizar con p y q grandes. Si el generador construye n con un factor diminuto (por ejemplo n = primo_grande · q con q de apenas 20 bits), n se factoriza al instante por división por primos pequeños. Recuperado q, se obtiene p = n / q, luego phi = (p-1)(q-1) y la clave privada d = e⁻¹ mod phi. Con la privada reconstruida se vuelve a firmar el token cambiando el claim que interese (un role de customer a administrator).
import sympy, jwt, base64
# n y e salen del campo jwk del token
factors = sympy.factorint(n) # n tiene un factor pequeño: cae al momento
p, q = list(factors.keys())
d = pow(e, -1, (p-1)*(q-1))
key = RSA.construct((n, e, d, p, q))
payload['role'] = 'administrator'
print(jwt.encode(payload, key.export_key(), algorithm='RS256'))No siempre se dan las dos condiciones a la vez: a veces basta con la clave embebida (si el servidor la acepta sin más), y otras con la factorización (si la pública es conocida pero débil). Aquí coincidían.
Cómo detectarlo. La firma es un JWT que llega con una clave embebida en la cabecera (jwk/jku/x5c), que un servidor bien configurado nunca debería aceptar: un gateway/WAF que inspeccione la cabecera del token puede marcar o rechazar cualquier jwk entrante. En el lado servidor, la aceptación de un token firmado con una clave distinta de la de confianza, o un token cuyo claim de rol/privilegio cambia entre peticiones de la misma sesión, es el indicador. Un n (módulo) con factores pequeños en las claves emitidas es la debilidad de fondo a auditar.
Defensa. No validar nunca contra una clave incluida en el token; usar una pública fija y de confianza. Generar las claves RSA con una librería seria (módulos de 2048 bits con dos primos grandes), nunca a mano.
Máquinas donde se aplica
- YummyHackTheBox