JWT Attacks
Arsenal completo de comandos en la cheatsheetUn JWT (JSON Web Token) es el formato más extendido para mantener una sesión sin estado en APIs. Son tres partes en Base64URL separadas por puntos, cabecera.payload.firma, y siempre empiezan por ey (es el {" inicial codificado). La cabecera dice el algoritmo (alg, típicamente HS256), el payload lleva los datos de la sesión (claims: id de usuario, rol, caducidad exp...) y la firma los sella con una clave que solo el servidor conoce.
El detalle clave es que el payload no está cifrado, solo codificado: cualquiera puede leerlo (pegándolo en jwt.io o decodificando el Base64). Lo que impide falsificarlo es la firma. De ahí salen los abusos habituales:
- Token filtrado/codificado en duro. Si un JWT válido aparece en un sitio donde no debería (el código de una app móvil, un repositorio, un log), se reutiliza tal cual. Es lo que ocurre aquí: un token de rol
Adminestaba grabado en el.apk, y con él la API concede acceso administrativo. Para enviarlo basta añadir la cabeceraAuthorization:
curl -X GET "http://api.ejemplo.htb/api/v1/admin/list/users" \
-H "Authorization: eyJhbGciOiJIUzI1NiIs..."- Caducidad eterna. Un
exppuesto en un futuro absurdo (años más allá) hace que el token nunca expire; conviene mirarlo al decodificar. alg: noney secreto débil. Algunas implementaciones aceptan tokens sin firma (alg: none) o usan un secreto HMAC débil que se puede crackear offline (conhashcat -m 16500), y entonces se forjan tokens con el rol que se quiera.
Recetas de forja y crackeo
# 1) alg:none -> quitar la firma y cambiar el claim (rol/usuario)
python3 jwt_tool.py <JWT> -X a # genera variantes alg:none
python3 jwt_tool.py <JWT> -T # editar claims interactivamente
# 2) secreto HMAC debil -> crackear offline y firmar el token que quieras
hashcat -m 16500 jwt.txt <rockyou.txt> # 16500 = JWT (HS256/384/512)
python3 jwt_tool.py <JWT> -C -d <rockyou.txt> # crackeo con jwt_tool
python3 jwt_tool.py <JWT> -S hs256 -p '<secret>' -T # re-firmar con el secreto hallado
# 3) confusion de algoritmo RS256 -> HS256 (firmar con la CLAVE PUBLICA como secreto HMAC)
python3 jwt_tool.py <JWT> -X k -pk public.pem # usa la publica del server como clave HMAC
# 4) kid injection: el 'kid' apunta a un fichero/consulta bajo control
# kid = "../../../../dev/null" -> clave vacia -> firmar con secreto ""
# kid con SQLi -> devolver una clave conocidaVer forja con secreto filtrado y forja con JWK embebido y RSA factorizable.
Cómo detectarlo. La manipulación de tokens deja rastro en el servidor: un pico de fallos de validación de firma (JWT rechazados) mientras un mismo cliente prueba variantes es señal de forja o de crackeo del secreto. La cabecera alg: none o un cambio de alg (de RS256 a HS256, ataque de confusión de algoritmo) en un token entrante debe registrarse y alertar: ningún cliente legítimo baja el algoritmo. Un token con un exp absurdamente lejano, o el mismo token reutilizado desde IPs muy dispares, apunta a robo/reutilización. Como el payload es legible, un WAF/gateway puede inspeccionar alg y exp en tránsito. La clave defensiva es loguear y contar los rechazos de firma por origen, no solo aceptarlos silenciosamente.
Defensa. No incrustar tokens en clientes, firmar con secretos largos y aleatorios, rechazar alg: none, emitir caducidades cortas y validar el exp y el rol en el servidor en cada petición.