Introducción
Con motivo de la certificación de BurpSuite me he visto envuelto en la tarea de realizar los laboratorios de la academia de PortSwigger. Dicho esto, uno de los primeros temas que me gustaría documentar es la resolución de los laboratorios de JWT (JSON Web Token)
Según la propia documentación de PortSwigger al respecto, nos indican que JWT es un formato estandarizado que se utiliza para enviar data en notación JSON y encriptada entre sistemas. Normalmente se utiliza como cookie en los sitios web para la manejar la autenticación y autorización. Consta de tres partes:
- Header: Contiene metadata del token, por ejemplo: el tipo de algoritmo utilizado.
- Payload: Data que se desea tramitar (usuarios, permisos, etc.)
- Signature: La firma del token, esta ligada al contenido de las dos primeras secciones y es la encargada de validar la integridad de los datos.
Cada sección del JSON Web Token es separada por un punto.
Tómemos como ejemplo el token del primer laboratorio. Normalmente se ve de esta manera.
eyJraWQiOiI0NDkwMzFjYS1hM2UzLTQ1NmUtODA0YS1jODRmZDkwMmExNzciLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6ImFkbWluaXN0cmF0b3IiLCJleHAiOjE2Njg4OTc4NDJ9.sRhsf67Sw2ONGsGz8EIhftD4qPAE8f3UTxw8xfpnG9LTSeR0MlvMX7T7DNuEyvBwkJcLzz3X_YQh0-2TUM6a1MQ2Pnt7mCMMvrmYmBdAVfbB3xdCZ1zHIPWR3MhdBiXuKuiJTXfxQEA0JSMhHF8ub-F0yWFz8OG4zGuljUn3-dmf4prsTkRLsObOBvANlUd_qwyUHsNRgji7LjkqgzgnebU7q2pQSaMGD54ICESIxRg3vLfSV8yf18Ofa47agJONYLTzKE_FNyHe1EpOx2tH8GgXrySXFStnuOqOfj-dCJsxcwXs4-ycM4U8nC1dK4mebzdTojy4jpXQKdi-PGHWXA
Si lo llevamos a https://jwt.io/ obtendremos una visión más clara y veremos la data decodificada.
Esta web funciona como un debugger y nos permite analizar y modificar los tokens.
En las aplicaciones web más vulnerables nos encontraremos con que podemos modificar el JWT directamente sin validaciones, al contrario de las implementaciones más robustas, en donde no podremos forjar un JWT válido a menos que poseamos la secret key del server.
A lo largo de este writeup estaré utilizando exclusivamente BurpSuite con la extensión JWT Editor, pero también es posible realizar los laboratorios con otras herramientas.
Lab 1 - JWT authentication bypass via unverified signature
- Enlace: Lab: JWT authentication bypass via unverified signature
- Objetivo: Obtener acceso al panel
/admin
y borrar el usuario carlos.
Según el enunciado, nos indican que la aplicación web no está realizando una validación de la firma en el JWT, por lo tanto, podemos editarlo a antojo y seguirá siendo válido.
Accederemos al Lab e iremos a iniciar sesión con las credenciales que nos proporcionaron: wiener:peter
.
Luego actualizaremos la página e interceptaremos el tráfico para tratarlo con BurpSuite.
Enviamos la petición hacia el Repeater.
En la pestaña (1) JSON Web Token (JWT Editor - Plugin) podemos ver el token desglosado y decodificado. Se puede ver claramente que en la sección de Payload se está enviando (2) el usuario con el que iniciamos sesión.
Ya que sabemos que no se está validando la firma, todo lo que debemos hacer es impersonar al usuario administrator para ingresar al panel /admin
.
Una vez hecho esto, podemos copiar el JWT y actualizar la cookie de session de nuestro navegador y acceder al panel de administración, o bien, continuar con BurpSuite.
Desde Burp modificaremos la URL para consultar /admin
y vemos el panel de administración.
Ahora para borrar el usuario, podemos filtrar por la palabra “carlos” desde la respuesta en formato raw y encontraremos el path que se consulta para borrar el usuario /admin/delete?username=carlos
.
Hacemos una nueva petición hacia esta URL y seguimos la redirección.
Al consultar nuevamente el panel de administración veremos que el usuario carlos ya no existe y nos aparece el mensaje de que hemos resuelto el laboratorio.
Lab 2 - JWT authentication bypass via flawed signature verification
- Enlace: Lab: JWT authentication bypass via flawed signature verification
- Objetivo: Obtener acceso al panel
/admin
y borrar el usuario carlos.
En esta ocasión el nombre del laboratorio nos indica que si se está realizando validación en la signature pero está mal implementada y se puede abusar.
Accederemos al laboratorio, pasaremos la request por burpsuite y cambiaremos nuevamente el usuario a administrator. En esta ocasión al consultar /admin
nos arroja un error 401 Unauthorized.
Volviendo a la web de PortSwigger, hay una sección en la que se indica que en malas implementaciones se puede enviar un token sin signature.
Para hacer esto basta con eliminar la ultima sección del JWT pero manteniendo el punto al final.
Desde Burp hay una manera rápida de hacerlo usando el ataque none Singing Algorith lo cual ya adecúa el token con este método.
Con el token en este estado enviaremos nuevamente el request y vemos que esta vez si podemos acceder al panel de administración.
Ajustaremos la URL para eliminar el usuario carlos y habremos resuelto el laboratorio.
Lab 3 - JWT authentication bypass via weak signing key
- Enlace: Lab: JWT authentication bypass via weak signing key
- Objetivo: Obtener acceso al panel
/admin
y borrar el usuario carlos.
En esta ocasión nos indican que para resolver el laboratorio debemos aplicar fuerza bruta a la key utilizando el diccionario que nos proporcionan.
Comenzaremos por loguear a la página con las credenciales wiener:peter
como siempre. Posteriormente interceptaremos un request para obtener el JWT.
eyJraWQiOiJmMDViN2UzOC0yODk3LTRiYzAtODZmZS04MjYwYjk1MjE5ZmEiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY2ODkyMTAyNn0.wv5ygAomTUfaTvxO-cUzYK5BbLmaHfrwr6ZD5kRZYHc
Es importante considerar que para aplicar fuerza bruta, debemos poseer un JWT válido. Lo almacenaremos en el archivo jwt.txt
y en conjunto con el diccionario jwt-secrets.txt
ejecutaremos el siguiente comando en hashcat para crackear el secret.
1
.\hashcat.exe -a 0 -m 16500 jwt.txt jwt-secrets.txt
Al cabo de unos segundos Hashcat encuentra la contraseña secret1
.
Teniendo esta información, ahora deberemos forjar un nuevo JWT como el usuario administrador y la nueva key para que éste sea válido.
Utilizando jwt.io
Para modificar nuestro token iremos a https://jwt.io/ y lo pegaremos.
Luego solo deberemos cambiar el usuario a administrador
y agregar el secret obtenido para validar el token.
Llevamos el token hacia Burp y al consultar /admin
tenemos acceso.
Realizamos un nuevo request a /admin/delete?username=carlos
y estaría resuelto el laboratorio.
Utilizando Burpsuite
Para forjar un JWT token y firmarlo en burpsuite, primero deberemos ir al Decoder y codificar el secret en base64.
Obtendremos la string c2VjcmV0MQ==
la cual copiaremos de momento.
Ahora, en la pestaña JWT Editor Keys haremos lo siguiente:
- Presionar en New Symmetric Key.
- Generate.
- Reemplazar valor
k
por el obtenido de nuestra secret key en base64 que previamente copiamos.
Quedaría de la siguiente forma.
Al darle a OK ya tendríamos una key con la que podemos firmar nuestro JWT.
Volveremos al request y en la pestaña JSON Web Token para firmar el token.
- Click en Sign
- Nos aseguramos de seleccionar la key que acabamos de crear
- No modificamos nada más y le damos a OK.
Con esto automáticamente se actualizará el JWT en nuestro request.
Lo probamos contra el panel de administración y efectivamente tenemos acceso, por lo que podremos finalizar el laboratorio.
Lab 4 - JWT authentication bypass via jwk header injection
- Enlace: Lab: JWT authentication bypass via jwk header injection
- Objetivo: Obtener acceso al panel
/admin
y borrar el usuario carlos.
Como siempre comenzaremos con loguear el usuario wiener y capturar un request en burpsuite para obtener el JWT.
Modificaremos el usuario a administrator
y al emitir una petición veremos que no es suficiente para obtener acceso al panel de administración.
En este caso lo que debemos hacer es crear nuestra propia llave pública e incrustarla en el Header del JWT.
Para esto haremos lo siguiente:
- Ir a la pestaña JWT Editor Keys y crear una nueva key RSA.
- Generar una nueva key con los valores por defecto.
- Darle a OK para almacenarla.
Luego de esto iremos al request capturado y en la pestaña JSON Web Token modificaremos nuestro token para incrustar la Key recién creada.
Nos aparecerá una ventana emergente que solicitará la key a insertar.
Una vez hecho esto, ya estaría incrustada nuestra key en la cabecera del JWT, la cual quedaría de la siguiente forma.
1
2
3
4
5
6
7
8
9
10
11
{
"kid": "14183f10-f44d-4ed5-ad61-21f883b385df",
"typ": "JWT",
"alg": "RS256",
"jwk": {
"kty": "RSA",
"e": "AQAB",
"kid": "14183f10-f44d-4ed5-ad61-21f883b385df",
"n": "oq8Keb3kHTR7vqv8Bc6dVRkGXkW2128ACLHirfhIFD2qNW-pWVp9BW1-VM7mkcVFS6qDwtscpv8oOl22WfIvk3wPoWKySD8zGG4vust8WxQz-wn-kt_0M6sPfuCtQ8l0KCPWy7taMj_Mv61VfbmRguR8bS2HghSqzl9twVcVp_gl-g6PIX-Ugu5Zk3_sjshxgof1xqT26rKQRuMbTyI1QdDIrpNpe5zrE5z6zmH764UBTEzpfTOqDoR0AQuONVDh673R4DNwCvJrc4oQXbgmQ6ii-XhJ-DbEzEAxQgmY9-BE6V1pYkL8hNzwjxfxRxi0dd0bQUrUi-Y-ClnQhpuJCQ"
}
}
Es importante notar que este proceso se puede realizar manualmente pero es necesario que los kid
coincidan.
Si emitimos un nuevo request, veremos que ya podemos alcanzar el panel de administración.
Ya solo restaría como siempre realizar un request a /admin/delete?username=carlos
para borrar el usuario y completar el laboratorio.
Lab 5 - JWT authentication bypass via jku header injection
- Enlace: Lab: JWT authentication bypass via jku header injection
- Objetivo: Obtener acceso al panel
/admin
y borrar el usuario carlos.
A diferencia del laboratorio anterior donde creamos una llave e incrustabamos la llave pública en el header del JWT, lo que haremos ahora será hacerlo a través de jku
(JWK Set URL), lo cual nos permitirá indicar la URL de un servidor para validar la key.
Para esto deberemos crear una nueva key RSA o reutilizar la anterior. Copiamos la llave pública como en formato JWK.
Y la llevaremos al exploit server tal cual como se muestra en la imagen.
El formato en el que se debe depositar el JWK en el server es el siguiente. Es posible definir una o múltiples llaves.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"keys": [
{
"kty": "RSA",
"e": "AQAB",
"kid": "75d0ef47-af89-47a9-9061-7c02a610d5ab",
"n": "o-yy1wpYmffgXBxhAUJzHHocCuJolwDqql75ZWuCQ_cb33K2vh9mk6GPM9gNN4Y_qTVX67WhsN3JvaFYw-fhvsWQ"
},
{
"kty": "RSA",
"e": "AQAB",
"kid": "d8fDFo-fS9-faS14a9-ASf99sa-7c1Ad5abA",
"n": "fc3f-yy1wpYmffgXBxhAUJzHql79gNNQ_cb33HocCuJolwDqmk6GPM4Y_qTVX67WhsN3JvaFYw-dfg6DH-asAScw"
}
]
}
Una vez realizado esto, iremos a editar nuestro token desde el request capturado en el Repeater.
- El
kid
del token debe coincidir con el depositado en el server. - Agregaremos el item
jku
en el header, el cual contendrá la URL del server en donde estará la llave pública. - Modificaremos el usuario para autenticarnos como
administrator
. - Finalmente firmaremos el token com la misma llave RSA sin modificar los headers.
Una vez hecho esto, emitiremos un request a /admin/delete?username=carlos
con el nuevo JWT para finalizar el laboratorio.
Lab 6 - JWT authentication bypass via kid header path traversal
- Enlace: Lab: JWT authentication bypass via kid header path traversal
- Objetivo: Obtener acceso al panel
/admin
y borrar el usuario carlos.
Comenzaremos con capturar un request una vez logueados para analizar el JWT.
Antes de modificar los datos del token, le daremos un vistazo a este tipo de ataque según PortSwigger.
Nos indican que en este caso es posible realizar Directory Traversal en el item kid
del Header JWT. Lo más comun es utilizar esto para apuntar a un archivo dentro del sistema, esto provocará que el servidor intentará autenticar nuestro JWT contra lo que sea que contenga este archivo.
Un método simple de explotar esto es realizar Directory Traversal para apuntar a /dev/null
lo que retornará null
. Si podemos generar una llave firmada con un byte null
esta será válida y podremos autenticarnos. Dicho esto, iremos a JWT Editor Keys y crearemos una nueva llave simétrica e insertaremos un null byte
codificado en base64 en el campo k
.
El
null byte
en base64 es representado comoAA==
Una vez ya tenemos nuestra key, haremos lo siguiente:
- Modificaremos el campo
kid
para apuntar a/dev/null
. - Impersonar al usuario administrator
- Firmar el token con la llave simétrica previamente creada.
- Seleccionar la key correcta y aplicar la firma.
Con esto ya podremos ingresar al panel de administración.
Y borraremos al usuario carlos.
Lab 7 - JWT authentication bypass via algorithm confusion
- Enlace: Lab: JWT authentication bypass via algorithm confusion
- Objetivo: Obtener acceso al panel
/admin
y borrar el usuario carlos.
Para explicar en palabras simples el ataque Algorithm Confusion se trata de un método para “engañar” al sever y utilizar otro tipo de algoritmo de verificación. Existen los algoritmos simétricos como HS256 (HMAC + SHA-256) en donde se usa una única clave tanto para firmar como para verificar el token.
Por otro lado, algoritmos como RS256 (RSA + SHA-256) usan un par de llaves asimétricas. Las que consisten en una llave privada, la cual el server utiliza para firmar el token, y una llave pública relacionada a esta primera llave que se utilizará para verificar la firma.
Dicho esto, en malas implementaciones se puede abusar este concepto para “engañar” a un server que esté esperando verificación asimétrica y enviarle un token firmado simétricamente. Para que esto funcione se requerirán un par de cosas que veremos más adelante.
Más detalle sobre Algorithm Confusion
Para comenzar capturaremos un request de una sesión logueados como el usuario wiener. Como es de esperar, no tendremos acceso al panel de administración de una vez.
Lo primero para el ataque, será obtener la llave pública desde el server. Según PortSwigger, las rutas comunes son: /jwks.json
ó /.well-known/jwks.json
.
En este caso, la llave está almacenada en /jwks.json
.
Copiaremos el contenido del array keys
.
Creamos una nueva RSA Key en formato JWK y pegaremos la llave.
Una vez creada, copiaremos la llave pública en formato PEM.
La llevaremos al Decoder, pegamos el contenido y lo codificaremos en Base64. Copiaremos la string obtenida.
Lo siguiente será crear una nueva Symmetric Key e insertar el valor obtenido anteriormente en el campo k
.
Con la llave simétrica creada, volveremos al request y forjaremos un nuevo JWT. Se debe modificar el campo alg
en el Header a HS256 y obviamente impersonaremos al usuario administrator.
Finalmente firmaremos el JWT con la llave simétrica.
Ya podremos acceder al panel de administración.
Y eliminamos el usuario carlos.
Lab 8 - JWT authentication bypass via algorithm confusion with no exposed key
- Enlace: Lab: JWT authentication bypass via algorithm confusion with no exposed key
- Objetivo: Obtener acceso al panel
/admin
y borrar el usuario carlos.
Para este laboratorio, se utilizará la misma técnica Algorithm Confusion solo que esta vez la llave pública no está expuesta en el servidor. Por lo tanto, tendremos que aplicar fuerza bruta para conseguirlo.
Capturaremos un request una vez logueados.
Para poder aplicar fuerza bruta en la aplicación, deberemos contar primero con dos JWT válidos. Para conseguirlos, solamente debemos capturar un request, extraer el token, cerrar sesión y volver a iniciar sesión para obtener el segundo token.
Una vez obtenidos ambos token, podemos utilizar una herramienta de PortSwigger a través de docker, a la cual solo le debemos proporcionar los token anteriormente obtenidos.
1
docker run --rm -it portswigger/sig2n <token1> <token2>
Al cabo de unos minutos obtendremos lo siguiente:
Una llave PEM codificada en Base64 en los formatos X.509 y PKCS1.
Un JWT forjado utilizando estas llaves.
Con esto, lo que queremos extraer son los JWT y remplazarlos en nuestro request capturado para verificar que sean válidos al emitir una petición a /my-account
. En este caso el JWT 1 me arrojó una respuesta HTTP 301
(redirección) ya que no fué válido y la web nos devolvió al menú de login.
El JWT 2 si resultó válido.
Ya con esta información, lo que sigue es obtener la cadena en Base64 de la llave pública en formato X.509 perteneciente al JWT válido.
La utilizaremos para crear una nueva Symmetric Key e insertarla en k
.
Con la llave creada, ya solo resta impersonar el usuario administrator
en el payload del token y firmarlo utilizando la llave simétrica recién creada.
Ya podremos ingresar al panel de administración
Y borrar el usuario carlos.
Con esto concluyen los laboratorios de PortSwigger relacionados a JWT.