Explotación de Json Web Tokens (JWT) y vulnerabilidades

    Los Json Web Tokens (JWT) son un tipo de token utilizado en la autenticación y autorización de usuarios en aplicaciones web. JWT es un estándar abierto (RFC 7519) que define un formato compacto y seguro para transmitir información entre diferentes partes de forma confiable.




    A diferencia de los tokens de sesión clásicos, todos los datos que necesita un servidor se almacenan en el lado del cliente dentro del propio JWT. Esto hace que los JWT sean una opción popular para sitios web altamente distribuidos donde los usuarios necesitan interactuar sin problemas con múltiples servidores back-end

    Un JWT consta de 3 partes: un encabezado, una carga útil y una firma. Cada uno de ellos está separado por un punto, como se muestra en el siguiente ejemplo:


    Las partes de encabezado y carga útil de un JWT son solo objetos JSON codificados en base64url. El encabezado contiene metadatos sobre el token en sí, mientras que la carga contiene las “reclamaciones” reales sobre el usuario. Por ejemplo, puede decodificar la carga útil del token anterior para revelar las siguientes afirmaciones:


    En la mayoría de los casos, cualquier persona con acceso al token puede leer o modificar fácilmente estos datos. Por lo tanto, la seguridad de cualquier mecanismo basado en JWT depende en gran medida de la firma criptográfica.

    El servidor que emite el token generalmente genera la firma mediante el hash del encabezado y la carga útil. En algunos casos, también cifran el hash resultante. De cualquier manera, este proceso implica una clave secreta. Sin conocer este secreto, no es posible generar una firma válida para un encabezado y una carga útil determinados. Cualquier cambio en el encabezado o la carga útil significaría que la firma ya no coincide. Esto proporciona una forma para que los servidores verifiquen que ninguno de los datos ha sido manipulado desde que se emitió el token porque

    Los ataques JWT involucran a un usuario que envía JWT modificados al servidor para lograr un objetivo malicioso. Por lo general, este objetivo es eludir la autenticación y los controles de acceso haciéndose pasar por otro usuario que ya se ha autenticado.



¿Cómo surgen las vulnerabilidades a los ataques JWT?


    
Las vulnerabilidades de JWT suelen surgir debido a un manejo defectuoso de JWT dentro de la propia aplicación. Las diversas especificaciones relacionadas con los JWT tienen un diseño relativamente flexible, lo que permite a los desarrolladores de sitios web decidir muchos detalles de implementación por sí mismos. Esto puede resultar en que introduzcan vulnerabilidades accidentalmente incluso cuando se usan bibliotecas reforzadas.

    Estas fallas de implementación generalmente significan que la firma del JWT no se verifica correctamente. Esto permite que un atacante manipule los valores pasados ​​a la aplicación a través de la carga útil del token. Incluso si la firma se verifica sólidamente, si realmente se puede confiar en ella depende en gran medida de que la clave secreta del servidor permanezca en secreto. Si esta clave se filtra de alguna manera, o se puede adivinar o utilizar la fuerza bruta, un atacante puede generar una firma válida para cualquier token arbitrario, comprometiendo todo el mecanismo.


Explotación de verificación de firma JWT defectuosa


    Por diseño, los servidores no suelen almacenar ninguna información sobre los JWT que emiten. En cambio, cada token es una entidad completamente autónoma. Esto tiene varias ventajas, pero también presenta un problema fundamental: el servidor en realidad no sabe nada sobre el contenido original del token, ni siquiera cuál era la firma original. Por lo tanto, si el servidor no verifica la firma correctamente, no hay nada que impida que un atacante realice cambios arbitrarios en el resto del token.

Por ejemplo, considere un JWT que contenga las siguientes afirmaciones:

{ "username": "carlos", "isAdmin": false }

    Si el servidor identifica la sesión en función de este username, la modificación de su valor podría permitir que un atacante se haga pasar por otros usuarios que iniciaron sesión. De manera similar, si el isAdminvalor se usa para el control de acceso, esto podría proporcionar un vector simple para la escalada de privilegios.

    Hay una vulnerabilidad muy conocida en las versiones ciertas bibliotecas en las que se puede engañar al servidor que espera que los tokens firmados mediante criptografía asimétrica acepten un token firmado simétricamente. El quid de la cuestión es que al cambiar el algoritmo del token de ‘RS’ a ‘HS’, un endpoint vulnerable utilizará su clave pública para verificar el token de forma simétrica (y al ser pública, esa clave no es muy secreta).

    Una sola desviación de bits obtendrá un resultado diferente a la otra. Y ese es un problema con este ataque: si la clave pública que usamos para falsificar una firma es de alguna manera diferente a la clave que el servidor está usando para verificar la firma, una implementación vulnerable puede no ser reportada.


PoC


    Se trata de un servidor web de Flask que es un framework minimalista escrito en Python que permite crear aplicaciones web rápidamente y con un mínimo número de líneas de código.

A continuación se muestra parte del código de la web en el que se ve cómo se generan y validan los tokens, entre otras cosas.


El index de la web tiene el siguiente aspecto:


Y a través de ella nos permite registrarnos en la página, en la que podemos comprar caballos y competir en carreras con ellos.


Para poder participar en las carreras se necesita un caballo:


Sin embargo, al solo disponer de 100$ no se pueden comprar caballos capaces de batir al “campeón actual”.


Vamos a capturar alguna petición con BurpSuite para poder analizar el token:


Las tres partes del token van separadas por puntos (“.”):

cabecera.datos.firma

Estas partes están codificadas en base64:

Llegados a este punto, podrías generar un token modificando algunos de los datos, pero antes de crear nuevos tokens dándonos, por ejemplo, más dinero, vamos a leer el código del servidor:


El primer endpoint nos carga la plantilla main.html en caso de tener un token correcto en nuestras cookies y nos lleva a new_user.html en caso de no tener un token o no ser correcto.
Al registrarnos se nos crea un token:


Lo realmente interesante está en el endpoint /do_race:


Primeramente se comprueba que el token sea correcto y el siguiente paso es comprobar si la velocidad de nuestro caballo es superior a la del campeón.
Estas velocidades se calculan con las lineas:


Así que el objetivo es encontrar un caballo cuyo md5 en hexadecimal sea mayor que el md5 en hexadecimal que el campeón:


Una vez sabemos el nombre de nuestro caballo, debemos generar el token. Es importante cambiar el algoritmo a “HS256”:


Finalmente firmarlo con la clave pública que se nos incluye en el código fuente:


Con las lineas anteriores ya tenemos un token correcto, podemos probarlo haciendo la petición a /do_race:




2 comentarios:

  1. consulta , ya que estas cambiando el algoritmo a HS y firmando con la llave publica que nos incluye el codigo fuente , de paso se podria cambiar el valor del dinero en money=100 ya que comenzamos con ese dindero le pones 00 mas y envias el jwt ya cambiado el algoritmo y ya con la firma publica. Funcionaria?

    ResponderEliminar