¡Hola a todos! Aquí estamos de nuevo y esta vez seguimos preparando la certificación Burp Suite Certified Professional (BSCP), que proporciona una base muy buena de cara a auditorías web y gestión de la presión, sobre todo en el examen para el cual te proporcionan 4 horas y hay que explotar hasta 6 vulnerabilidades. Además, se trata de un examen muy barato (<100€) lo que la hace sumamente atractiva.
Antes de nada, recordad que PortSwigger nos permite probar 30 días su versión profesional de Burp Suite. Os recomendamos que activéis esta versión para poder probar todas las funcionalidades de la herramienta.
En esta entrada explicaremos y solucionaremos todos los laboratorios relativos a JWT (JSON Web Tokens). Hay muchos walkthroughs sobre cómo resolver estos laboratorios, pero exponerlos aquí nos sirve para afianzar conceptos y enseñaros además algunos trucos de uso de Burp Suite Professional, así como comentar veces que hemos visto las vulnerabilidades estudiadas en los laboratorios en la vida real. Sin más dilación, ¡comenzamos!
Cada vez más sitios utilizan este tipo de tokens para autenticar usuarios o realizar checks de autorización. Normalmente, suelen encontrarse bien implementados, pero en algunos casos los desarrolladores no verifican adecuadamente las propiedades de los tokens o confían ciegamente en características de seguridad (como el firmado) que no son tal por sí mismas. Por ello, este post adquiere muchísima relevancia dado que es fundamental entender cómo funcionan estos mecanismos y saber auditarlos.
Lab1 (Apprentice) – JWT authentication bypass via unverified signature
Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.
En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, modify your session token to gain access to the admin panel at /admin, then delete the user carlos.». En este laboratorio el objetivo es explotar vulnerabilidades en el JWT para obtener acceso como administrador.
Comenzamos mapeando la aplicación y nos damos cuenta que, al iniciar sesión como el usuario «wiener:peter», obtenemos un JWT en forma de cookie:

Mandamos la petición de acceso a información del usuario a Repeater y, con la extensión JWT Editor, retocamos el token JWT con el objetivo de manipularlo, de tal modo que indiquemos que el usuario asociado al token es «administrator»:


Se puede observar en las imágenes anteriores que se obtiene acceso como administrador al manipular el JWT. Esto es así porque el servidor no verifica en ningún momento su firma. Si la verificase, no podríamos haber forjado un nuevo token ya que a priori desconocemos la clave secreta de firmado. Así las cosas, lanzamos ahora el borrado del usuario «carlos» para resolver el laboratorio. Simplemente ve navegando al endpoint «/admin» primeramente y luego al endpoint «/admin/delete?username=carlos» con el nuevo token:

Lab2 (Apprentice) – JWT authentication bypass via flawed signature verification
Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.
En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, modify your session token to gain access to the admin panel at /admin, then delete the user carlos.». En este laboratorio el objetivo es explotar vulnerabilidades en el JWT para obtener acceso como administrador.
Comenzamos mapeando la aplicación y nos damos cuenta que, al iniciar sesión como el usuario «wiener:peter», obtenemos un JWT en forma de cookie:

Seguimos el mismo procedimiento que en el caso anterior. Reenviamos la petición al endpoint de «/my-account?username=administrator» con el token original y tratamos de manipularlo, haciendo creer al servidor que somos otro usuario. Para ello, probamos en primer lugar a cambiar el contenido del payload:

Sin embargo, obtenemos una redirección al login, lo cual nos indica que el JWT es inválido. Como siguiente prueba, intentaremos enviar al servidor un JWT cuyo algoritmo de signing sea «none», es decir, ninguno. Con ello, intentamos que el servidor no verifique la firma porque nosotros le indicamos que no hay ninguna. Para ello, utilizamos de nuevo JWT Editor:

El servidor acepta nuestro token con algoritmo de firmado «none». Como vemos, aunque se retocó el payload, se pudo acceder al panel del usuario «administrator». Por tanto, para resolver el laboratorio simplemente hay que enviar una petición a «/admin/delete?username=carlos» con el token nuevo:

Lab3 (Practicioner) – JWT authentication bypass via weak signing key
Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.
En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, first brute-force the website’s secret key. Once you’ve obtained this, use it to sign a modified session token that gives you access to the admin panel at /admin, then delete the user carlos.». En este laboratorio el objetivo es explotar vulnerabilidades en el JWT para obtener acceso como administrador.
Comenzamos mapeando la aplicación y nos damos cuenta que, al iniciar sesión como el usuario «wiener:peter», obtenemos un JWT en forma de cookie:

En este caso, podemos probar a incluir firmas arbitrarias o incluso JWT sin firma, pero nada de ello funcionará. Como tercera prueba, intentamos romper la clave de firmado del JWT con hashcat. Usamos para ello el siguiente comando (válido Kali Linux):
hashcat -a 0 -m 16500 <jwt> <wordlist>


Podemos observar que con hashcat obtenemos la clave usada para firmar los tokens JWT: secret1. Por tanto, ahora podemos forjar tokens arbitrarios. Para ello, importamos la clave de firmado en JWT Editor como «New Symmetric Key» y ahora manipulamos el token pero siempre que terminemos usamos la opción de firmarlo para que la extensión calcule el hash y lo añada al propio JWT. Repetimos el proceso de acceder al panel del usuario «administrator» que es «/my-account?username=administrator» pero esta vez con un token arbitrario firmado por nosotros:


Y, lanzando la petición, vemos que tenemos acceso al panel de administración, dado que hemos impersonado al usuario «administrator» forjando un token válido:

Para finalizar el laboratorio, simplemente debemos proceder con el borrado de «carlos» en el endpoint adecuado:

Lab4 (Practicioner) – JWT authentication bypass via weak signing key
Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.
En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, modify and sign a JWT that gives you access to the admin panel at /admin, then delete the user carlos.». En este laboratorio el objetivo es explotar vulnerabilidades en el JWT para obtener acceso como administrador.
Una vez más, observamos cómo al iniciar sesión se genera un JWT utilizado para la autenticación en el sitio web:

En este caso, al decodificar el token, podemos observar cómo se incluye en la cabecera el algoritmo «RS256», indicativo de que se utilizan claves asimétricas (clave pública y privada) para el firmado del token.

Debido a ello, intentaremos un ataque basado en crear un par de claves privada y pública autofirmadas, utilizándolas para firmar el token que enviaremos al servidor. Lo que haremos será calcular la firma en base a la clave privada y enviarle al servidor la pública, con la esperanza de que acepte cualquier par de claves y no solo los que «conoce». Utilizamos para ello JWT Editor, nuestra navaja suiza para manejo de JWT:

Tras generar la clave, mandaremos un JWT al endpoint «/my-account?id=administrator» con un token manipulado impersonando al usuario «administrator». En este caso, haremos un ataque «Embedded JWK» con JWT Editor, seleccionando la clave anterior:

Como podemos ver, el servidor acepta el JWT que hemos enviado, que va realmente firmado con la clave privada asociada a la clave pública que especificamos en el campo «jwk». Gracias a ello, vemos el panel de administración del sitio web. Concluimos, por tanto, que el servidor acepta claves asimétricas arbitrarias. Finalmente, usamos el nuevo token para borrar el usuario «carlos» en el endpoint correspondiente:

Lab5 (Practicioner) – JWT authentication bypass via jku header injection
Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.
En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, forge a JWT that gives you access to the admin panel at /admin, then delete the user carlos.«. En este laboratorio el objetivo es explotar vulnerabilidades en el JWT para obtener acceso como administrador.
Una vez más, observamos cómo al iniciar sesión se genera un JWT utilizado para la autenticación en el sitio web:

De nuevo, se puede observar el uso de algoritmo «RS256». Sin embargo, en este caso, el servidor no soporta el parámetro «jwk» en el que incluir nuestra clave pública. Sin embargo, soporta el parámetro «jku» en el que incluir una URL a un set de JWKs. Por tanto, explotamos dicho vector. Para ello, con JWT Editor lanzamos un ataque de «Embedded Collaborator Payload» para probar este punto:

Como vemos, no logramos acceso. Pero si accedemos a Burp Collaborator, vemos que el servidor ha intentado obtener las claves públicas para verificar la firma:

Así las cosas, podremos crear en JWT Editor una clave RSA asimétrica aleatoria y obtener los parámetros de su JSON asociado necesarios para la verificación de la clave pública. En nuestro caso, son los siguientes:
{
"kty": "RSA",
"e": "AQAB",
"kid": "4f9ae502-93ec-4e83-9017-60e1ee15f15c",
"n": "racodV5aCziTEVo9ZmeJ14wqV-BNqYPG56rEZuakRfU_qsEXEnTzTrJ8JFtM_ZBg-U4kjFBysSGtgYCLyW-z3l6c9EXlBD_nHFaxUFmXBGN18M-u8KS2v_N9Y2rH9sQV5oAkiHVAaRZ2ZCfEGANPpx6EBiEvpvF41uWt2KS7rP8FW0z_q7i_Vgpr7A1X34dd-zYciskgYQ4q7xsbKCcbDXegK2XZ76T1M1NLHxNW3LaT_DqyibR-qFhEDmuUEaS4hvWuKHgublTq4NYRzfxnhCrenMotOPDTQA2OvaPpLw6af47NmwFQZg0v1qXThHrZqd64Yn5d745GVzwJCFxXnw"
}
Para que el servidor que valida los tokens pueda intentar obtener estos valores, debemos servirlos en nuestro «Exploit Server» con el formato adecuado (es el siguiente, según la especificación de JWT):
{
"keys":
[
{
"kty": "RSA",
"e": "AQAB",
"kid": "4f9ae502-93ec-4e83-9017-60e1ee15f15c",
"n": "racodV5aCziTEVo9ZmeJ14wqV-BNqYPG56rEZuakRfU_qsEXEnTzTrJ8JFtM_ZBg-U4kjFBysSGtgYCLyW-z3l6c9EXlBD_nHFaxUFmXBGN18M-u8KS2v_N9Y2rH9sQV5oAkiHVAaRZ2ZCfEGANPpx6EBiEvpvF41uWt2KS7rP8FW0z_q7i_Vgpr7A1X34dd-zYciskgYQ4q7xsbKCcbDXegK2XZ76T1M1NLHxNW3LaT_DqyibR-qFhEDmuUEaS4hvWuKHgublTq4NYRzfxnhCrenMotOPDTQA2OvaPpLw6af47NmwFQZg0v1qXThHrZqd64Yn5d745GVzwJCFxXnw"
}
]
}
Por tanto, almacenamos dicho contenido en el «Exploit Server» bajo el recurso «jwks.json» y lanzamos de nuevo el ataque al endpoint «/my-account?id=administrator», eso sí cambiando el valor de los parámetros «jku» y «kid» en la cabecera del JWT por la URL de nuestro «Exploit Server» y el identificador de nuestra clave respectivamente. Asimismo, firmamos el token con la clave que acabamos de crear (resaltamos los cambios en la siguiente figura):

Tras ello, lanzamos la petición para ver el panel de administración:

¡Magia! Bueno… Más que magia, teoría de JWT. Estamos generando un par de claves privada/pública RSA. Firmamos el token con nuestra clave privada y a su vez exponemos la clave pública en una URL que añadimos al token en su parámetro «jku» de la cabecera. Dado que el servidor confía en ese parámetro, intenta verificar la firma con la clave pública que nosotros hemos publicado (valga la redundancia) en dicha URL y, como todo coincide, premio gordo. Ahora, simplemente, nos queda borrar el usuario «carlos»:

Lab6 (Practicioner) – JWT authentication bypass via kid header path traversal
Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.
En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, forge a JWT that gives you access to the admin panel at /admin, then delete the user carlos.«. En este laboratorio el objetivo es explotar vulnerabilidades en el JWT para obtener acceso como administrador.
Una vez más, observamos cómo al iniciar sesión se genera un JWT utilizado para la autenticación en el sitio web:

En este laboratorio, puedes probar todas las técnicas anteriores, pero ninguna funciona. Sin embargo, vemos que el firmado utilizado es simétrico y que se soporta el parámetro «kid». En estos casos, siempre debemos probar directorio transversal para saber si se puede firmar el token con el contenido de un fichero arbitrario cuyo valor es conocido.
Un buen objetivo es el fichero «/dev/null». Dado que si conseguimos explotar directorio transversal sabemos que la clave de firma es nula, debemos forjar el JWT y firmarlo con un valor nulo. Para ello tenemos un ataque disponible en JWT Editor denominado «Sign with an empty key». Manipulamos el JWT y cuando lo tenemos todo preparado, lanzamos dicho ataque para que se firme con el valor nulo como clave. La URL accedida será «/my-account?id=administrator»:

Y… Como vemos… Acceso concedido. Lógicamente, el servidor verifica que el JWT tiene su firma calculada con el valor nulo y, como en el parámetro «kid» especificamos un valor que lleva al servidor a pensar que la clave reside en «/dev/null», cuyo contenido es justamente nulo, todo cuadra perfectamente. Las claves de firmado de Burp y del servidor son idénticas. Finalmente, borramos el usuario «carlos»:

Lab7 (Expert) – JWT authentication bypass via algorithm confusion
Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.
En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, first obtain the server’s public key. This is exposed via a standard endpoint. Use this key to sign a modified session token that gives you access to the admin panel at /admin, then delete the user carlos.«. En este laboratorio el objetivo es explotar vulnerabilidades en el JWT para obtener acceso como administrador.
Una vez más, observamos cómo al iniciar sesión se genera un JWT utilizado para la autenticación en el sitio web:

Vemos, además, que se usan a priori claves asimétricas. Asimismo, ninguna de las técnicas anteriores funciona, así que intentaremos un ataque de key confusion. Estos ataques se basan en indicar al servidor que utilizamos un algoritmo simétrico para la firma. Si el servidor contiene lógica errónea, podría interpretar que el token debe ser firmado con la clave pública (es lo que él espera) como clave simétrica. Esto es, si logramos obtener la clave pública tal como el servidor la lee, podemos firmar el JWT.

Accedemos a la siguiente URL y obtenemos la clave pública que usa el servidor en formato JWK:
https://0aed008d039d5471843fd62f00db004c.web-security-academy.net/jwks.json

Ahora, utilizamos JWT Editor para hacer las siguientes operaciones. Revisa la documentación de PortSwigger al respecto, ya que son muchos pasos y esa documentación es muy completa.
- Creamos una nueva clave RSA a partir de la clave JWK, pegando el contenido
- Tras pegar el contenido, la pasamos a formato PEM, que es el formato más probable en el que esté en el servidor. Verás que la clave se convierte automáticamente. Dale a crear clave
- Una vez creada, botón derecho en la clave y copiar como PEM
- Cogemos el contenido de la clave PEM y lo llevamos a Burp Decoder para codificarlo en Base64
- Generamos una nueva clave simétrica aleatoria (botón generate de JWT Editor dentro del menú de crear clave simétrica)
- Una vez tenemos la clave simétrica aleatoria, cambiamos el valor del parámetro «k» por el contenido en Base64 anterior

Con todos los pasos anteriores, hemos convertido la clave pública en formato JWK a su clave simétrica equivalente si el servidor usa algoritmos de este tipo. Ahora nos queda únicamente manipular el token, firmarlo con esta clave simétrica y utilizar algoritmos simétricos para enviar el token a su verificación en el lado de servidor (algorithm confusion, dado que no lo espera). Obviamente, atacamos el endpoint deseado «/admin».

De nuevo, simplemente siguiendo la ruta a «/admin/delete?username=carlos» con el mismo token, resolvemos el laboratorio.
Lab8 (Expert) – JWT authentication bypass via algorithm confusion with no exposed key
Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.
En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, first obtain the server’s public key. Use this key to sign a modified session token that gives you access to the admin panel at /admin, then delete the user carlos.«. En este laboratorio el objetivo es explotar vulnerabilidades en el JWT para obtener acceso como administrador.
Una vez más, observamos cómo al iniciar sesión se genera un JWT utilizado para la autenticación en el sitio web:

Nuevamente, las técnicas anteriores no funcionan. Asimismo, no tenemos la clave pública como en el laboratorio anterior. Sin embargo, a través de dos JWT podemos obtenerla tal como nos explica PortSwigger con el siguiente comando (ojo, que necesitas docker para lanzarlo):
docker run --rm -it portswigger/sig2n <token1> <token2>
Recogemos dos tokens válidos iniciando sesión dos veces como «wiener» y lanzamos el comando:
docker run --rm -it portswigger/sig2n eyJraWQiOiI1MzdiNjFmYS0xYTNlLTQxMjktYjAxNC0zNGY5NWIzNGM4ZDkiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsImV4cCI6MTc1OTYyOTkxMywic3ViIjoid2llbmVyIn0.NAGSrGgOz8EufgscHflzpv7GtgMnfatCq_SeIWBDMgoNR1My-KR3c7e5f18t9oXRJun5u7J1nw8d9m_JbyDuUCePiYL-teb6PNX6NGni_sxAGz4dLo_eHShiAlj_OyKB2ac44gN-ouUszjBIJhLrNyAoMpS5hLGmUQBCoSIP0H9qtsYJANf9oA55vhGGDZiJiuwT9VeF48jdcxl1FAL2Ve66Ih9GxQ8Sc2D5QATecp1IGU29O2dn0GEy44Avxf8ViO66XiLb-c4A740yTnGXz3tvD12BjPu6HB7ZMZG_saiuPwnTqgsAVOO2AsU3CCwhLBh7e2ORkyLNSOeFj02pnA eyJraWQiOiI1MzdiNjFmYS0xYTNlLTQxMjktYjAxNC0zNGY5NWIzNGM4ZDkiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsImV4cCI6MTc1OTYzMDA5MCwic3ViIjoid2llbmVyIn0.hKVe_sTf0Fkg1l2LS6EQIUnpYbJejV1T2bryW-jK0TbfyVA6P-ugnr69FgX3LLCUMyZwXf3LiPYRh4BPMV9nRTdE-da3FQRX0ZYZ8_5zNfKL4b8DMp7yw3CDGJKouzM0EBhm8MuaRhMF0WesdFeNwg3N5MseRn3C27SN9DbrDAjfNVox-aoWulJ2KJltGpTcn5SjAcZ9rJ3fi4DXwxhV2D6M_vTXOcbUFD6Ju9i4QUAgJ7Zf54OyUKJRr35BLNebLWiuQsQowRbUTckICcaNGV_keoXWTvGInUS7lE9SialJ8Nr4t-eaj7HuCvKX0GbTIolUteeMzuLIXczMsXpjbQ

La herramienta nos da varias posibles claves públicas y sus JWT asociados. Debemos probar todos ellos en una petición válida para saber cuál es la clave pública utilizada. Puedes probar uno a uno los tokens y el que funcione, ese será. En nuestro caso, sabemos que el servidor guarda la clave pública en formato x509, por lo que la clave obtenida interesante es la primera.
Ahora tienes dicha clave en Base64, por lo que solamente deberás importarla en JWT Editor y lanzar el ataque algorithm confusion (revisa el laboratorio anterior, pues se explica este punto). En cualquier caso, ahora es mucho más fácil ya que la conversión de la clave pública a simétrica no es necesaria.

Y, nuevamente, solo te queda borrar el usuario «carlos» en el endpoint «/admin/delete?username=carlos» con el token ya manipulado.
~km0xu95
Comments are closed.