# Vulnerabilidades JWT

## JSON Web Tokens <a href="#json-web-tokens" id="json-web-tokens"></a>

### General <a href="#general" id="general"></a>

Es un estándar basado en JSON (Javascript Object Notation) para la creación de tokens de acceso que permiten la propagación de identidad y privilegios. El token está firmado por la clave del servidor, así que el cliente y el servidor son ambos capaces de verificar que el token es legítimo.

Los JSON Web Tokens están diseñados para ser compactos, poder ser enviados en las URLs -*URL-safe*- y ser utilizados en escenarios de [Single Sign-On](https://es.wikipedia.org/wiki/Single_Sign-On) (SSO).

El estándar de JWT se basa en otros estándares basados en JSON [JSON Web Signature](https://es.wikipedia.org/wiki/JSON_Web_Signature) ([RFC 7515](https://tools.ietf.org/html/rfc7515)) y [JSON Web Encryption](https://es.wikipedia.org/w/index.php?title=JSON_Web_Encryption\&action=edit\&redlink=1) ([RFC 7516](https://tools.ietf.org/html/rfc7516))

JWT = Datos en JSON criptográficamente firmados

JWE = JWT encriptado

Consideraciones:

* Utilizar JWT previene de los ataques CSRF. Pero puede seguir siendo vulnerable si se almacena en una cookie.
* Si se almacena en *local storage*, es susceptible a ataques *XSS*.
* Los JWTs son buenos contra ataques de dominio cruzado (*cross domain*).

#### Estructura <a href="#estructura" id="estructura"></a>

Están formados por 3 partes:

```
HEADER.PAYLOAD.SIGNATURE
```

* Una cabecera o *header*. Indentifica el algoritmo utilizado para generar la firma.
  * Algoritmos aceptados:
    * RSA.
    * HMAC.
    * Elliptic Curve.
    * None.

      ```
        header = '{"alg":"HS256","typ":"JWT"}'
      ```
* Un contenido o *payload*. Contiene los privilegios del token.
  * Valores:
    * iss: issuer
    * iat: issued at
    * nbf: “not before” (start date)
    * sub: subject
    * exp: expires at
  * Puede contener cualquier información, como: Nombre de usuario, email, rol, permisos, contraseñas.

    ```
      payload = '{"loggedInAs":"admin","iat":1422779638}'
    ```
* Una firma digital o *signature*. Que se calcula codificando la cabecera y el contenido en base64, concatenándose con un punto.

  ```
    key           = 'secretkey'
    unsignedToken = encodeBase64Url(header) + '.' + encodeBase64Url(payload)
    signature     = HMAC-SHA256(key, unsignedToken)
  ```

Generalmente los algoritmos de cifrado utilizados son HMAC con [SHA-256](https://es.wikipedia.org/wiki/SHA-2) (HS256) y [firma digital](https://es.wikipedia.org/wiki/Firma_digital) con [SHA-256](https://es.wikipedia.org/wiki/SHA-2) (RS256).

#### Cómo detectar tokens JWT <a href="#como-detectar-tokens-jwt" id="como-detectar-tokens-jwt"></a>

Normalmente empiezan con `eyJ0eXAi` o `eyJhbGci`.

* `eyJ0eXAi`= `{"typ"`
* `eyJhbGci`= `{"alg"`

Y un punto en los primeros 40-60 caracteres.

#### Convertir de B64String to B64URL <a href="#convertir-de-b64string-to-b64url" id="convertir-de-b64string-to-b64url"></a>

Sustitución de caracteres:

`+` -> `-`

`/` -> `_`

`=` -> \` \` (se elimina)

#### Obtener información en texto plano <a href="#obtener-informacion-en-texto-plano" id="obtener-informacion-en-texto-plano"></a>

<https://jwt.io/>

Ej:

```
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Inh0b3JtaW4iLCJwayI6Ii0tLS0tQkVHSU4gUFVCTElDIEtFWS0tLS0tXG5NSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQTk1b1RtOUROemNIcjhnTGhqWmFZXG5rdHNiajFLeHhVT296dzB0clA5M0JnSXBYdjZXaXBRUkI1bHFvZlBsVTZGQjk5SmM1UVowNDU5dDczZ2dWRFFpXG5YdUNNSTJob1VmSjFWbWpOZVdDclNyRFVob2tJRlpFdUN1bWVod3d0VU51RXYwZXpDNTRaVGRFQzVZU1RBT3pnXG5qSVdhbHNIai9nYTVaRUR4M0V4dDBNaDVBRXdiQUQ3MytxWFMvdUN2aGZhamdwekhHZDlPZ05RVTYwTE1mMm1IXG4rRnluTnNqTk53bzVuUmU3dFIxMldiMllPQ3h3MnZkYW1PMW4xa2YvU015cFNLS3ZPZ2o1eTBMR2lVM2plWE14XG5WOFdTK1lpWUNVNU9CQW1UY3oydzJrekJoWkZsSDZSSzRtcXVleEpIcmEyM0lHdjVVSjVHVlBFWHBkQ3FLM1RyXG4wd0lEQVFBQlxuLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tXG4iLCJpYXQiOjE2MjY3MjA5NTR9.aWuLHlmBDuV3v_F0tCmbRz-pzoP4qCLcjfT4SQgN-Mq4hAfq_X16oiLhX9hKKIp2YMaaOwuW8-12o6vIHgUXDT6AZYTq2gX6mJLqYfGcqm6XLYMiINiTfVc8uZbGRl-wH5vs6je1L3qR6GcrmCNcAgjsDVbN61y7Vv2XMD5qZgwIBwZle4ZghRMG2hlDappWlHG_P7MbHExJvonlzGBxZAPV9w-01_dTiDcNLA7LW_suroK2l5GCxmvvCoCuyu0FnK6GpaKFKKOn9UZ0WqgC7i1HYqwJQHmWMsbEq-N-DrUnVppHviyaXnfAgsPb6U4dbMng32Hohyw7J6hkoXG9qA
```

### Ataques comunes <a href="#ataques-comunes" id="ataques-comunes"></a>

#### Fallo en la verificación de la firma <a href="#fallo-en-la-verificacion-de-la-firma" id="fallo-en-la-verificacion-de-la-firma"></a>

Muchas librerías JWT tienen un método para decodificar y otro para verificar el token:

* `decode()`. Decodifica el token sin verificar la firma.
* `verify()`. Decodifica y verifica el token.

Durante el desarrollo suele utilizarse el método `decode()` y cuando se pasa la aplicación a producción se suele olvidar cambiar el método por `verify()`.

#### Algoritmo *none* permitido <a href="#algoritmo-none-permitido" id="algoritmo-none-permitido"></a>

Si se cambia el algoritmo por *none* en alguna de sus siguientes variantes y se elimina el tercer campo del JWT dejando el punto final.

```
none
None
nOnE
NONE
```

Ej:

```
eyJhbGciOiJOb25lIiwidHlwIjoiSldUIn0.
eyJuYW1lIjoiSm9obiBEb2UiLCJ1c2VyX25hbWUiOiJqb2huLmRvZSIsImlzX2FkbWluIjp0cnVlfQ.
```

#### Confusión de algoritmos <a href="#confusion-de-algoritmos" id="confusion-de-algoritmos"></a>

Esta vulnerabilidad se da cuando la aplicación no comprueba que el algoritmo coincida con el algoritmo que se espera.

Muchas librerías no comprueban por defecto si el algoritmo coincide, por eso se utiliza la siguiente [Comprobación del algoritmo](https://xtormin.com/docs/pentesting/app-web/Sesiones/sessions/#comprobaci%C3%B3n-del-algoritmo) para verificarlo.

**ALGORITMOS**

| Algoritmo        | Clave de firma | Clave de verificación |
| ---------------- | -------------- | --------------------- |
| Asimétrico (RSA) | Clave privada  | Clave pública         |
| Simétrico (HMAC) | Contraseña     | Contraseña            |

> **Algoritmo asimétrico:** Cuando se utiliza una encriptación asimétrica, se publica la clave pública y se mantiene la clave privada en secreto. Esto permite firmar el token con la clave privada y que cualquiera pueda verificarla con la clave pública.

**RSA**

Si la clave pública está disponible, un atacante puede falsificar tokens:

* Cambiando el algoritmo del token por HMAC.
* Manipulando el resultado con el payload.
* Firmar el token con la clave pública detectada en la aplicación o en el JWT.
* Enviar el JWT de vuelta a la aplicación.

**HMAC**

La fortaleza de la firma vendrá determinada por la fortaleza de la contraseña. Si la aplicación utiliza una contraseña débil, se podrá llegar a obtener por medio de fuerza bruta.

**COMPROBACIÓN DEL ALGORITMO**

Normalmente las librerías comprueban el algoritmo de la siguiente manera:

* HMAC. `verify(token, secret)`.
* RSA o similar. `verify(token, secret)`.

### Ataques contra JWT <a href="#ataques-contra-jwt" id="ataques-contra-jwt"></a>

#### Inyección en parámetro *kid* <a href="#inyeccion-en-parametro-kid" id="inyeccion-en-parametro-kid"></a>

Si la cabecera contiene el parámetro `kid`, este normalmente es usado para obtener la clave de una base de datos o sistema de ficheros. La aplicación verifica la firma utilizando la clave obtenida en este parámetro.

Si el parámetro es inyectable, este podría ser utilizado para saltarse la firma o realizar ataques de RCE, SQLi o LFI.

**EJEMPLO**

**JWT Original**

```
{
  "alg": "HS256",
  "typ": "JWT",
  "kid": "key"
}.
{
  "name": "Jennifer Torres",
  "user_name": "jennifer.torres",
  "is_admin": false
}
```

**JWT con inyección**

```
{
  "alg": "HS256",
  "typ": "JWT",
  "kid": "key|/usr/bin/uname"
}.
{
  "name": "Jennifer Torres",
  "user_name": "jennifer.torres",
  "is_admin": false
}
```

#### Bypass de la firma <a href="#bypass-de-la-firma" id="bypass-de-la-firma"></a>

**INYECCIÓN EN PARÁMETRO&#x20;*****KID*****&#x20;+&#x20;*****DIRECTORY TRAVERSAL***

Si la aplicación utiliza el parámetro *kid* como valor de la clave utilizada para validar la firma, un atacante podría modificarlo por un fichero con el valor de la clave, por ejemplo, `/dev/null` y con ello saltársela.

**Ejemplo**

```
{
  "alg": "HS256",
  "typ": "JWT",
  "kid": "../../../../../../dev/null"
}.
{
  "name": "Jennifer Torres",
  "user_name": "jennifer.torres",
  "is_admin": true
}
```

**INYECCIÓN EN PARÁMETRO&#x20;*****KID*****&#x20;+&#x20;*****INYECCIÓN SQL***

Si la aplicación utiliza el parámtro *kid* para obtener la información de la base de datos como la clave de la firma, se podría intentar inyectar código SQL.

**Ejemplo de consulta SQL**

```
SELECT key FROM keys WHERE key='key'
```

**Ejemplo de inyección SQL en&#x20;*****kid***

```
{
  "alg": "HS256",
  "typ": "JWT",
  "kid": "test' UNION SELECT 'aaaa"
}.
{
  "name": "Jennifer Torres",
  "user_name": "jennifer.torres",
  "is_admin": true
}
```

**Consulta con inyección en&#x20;*****kid***

```
SELECT key FROM keys WHERE key='test' UNION SELECT 'aaaa'
```

La inyección `' UNION SELECT 'aaaa` permite a un atacante sustituir la clave por `aaaa` y con ello firmar el token con dicha clave para saltarse la firma.

#### Manipulación del parámetro *jku* <a href="#manipulacion-del-parametro-jku" id="manipulacion-del-parametro-jku"></a>

Este parámetro se utiliza para especificar el *JSON Web Key Set URL* ([RFC7515](https://datatracker.ietf.org/doc/html/rfc7515#section-4.1.2)), que indica donde se encuentra el *JSON Web Key* utilizado para verificar la firma.

**Ejemplo de JWT con&#x20;*****jku***

```
{
  "alg": "RS256",
  "typ": "JWT",
  "jku":"https://example.com/key.json"
}.
{
  "name": "Jennifer Torres",
  "user_name": "jennifer.torres",
  "is_admin": false
}
```

**Ejemplo de&#x20;*****JSON Web Key*****&#x20;(fichero key.json)**

```
{
  "kty": "RSA",
  "n": "-4KIwb83vQMH0YrzE44HppWvyNYmyuznuZPKWFt3e0xmdi-WcgiQZ1TC...RMxYC9lr4ZDp-M0",
  "e": "AQAB"
}
```

**FORMAS DE SALTARSE LAS LIMITACIONES**

* Utilizando `https://xtormin` si la aplicación solo comprueba el inicio de la URL (ej: `https://xtormin@attacker.com/key.json`).
* Utilizando fragmentos con el caracter `#`.
* Utilizando la jerarquía de nombres DNS.
* Concatenándolo con *open redirect*, *header injection* o *ssrf*.

\### Prevención

Para prevenirlo, se debe:

* Filtrar la URL correctamente.
* Añadir los hosts permitidos en *whitelist*.
* Prevenir otros ataques que puedan ser concatenados para saltarse las restricciones.

### Herramientas <a href="#herramientas" id="herramientas"></a>

### JWT Tool <a href="#jwt-tool" id="jwt-tool"></a>

<https://github.com/ticarpi/jwt_tool.git>

#### Extensión de Burp <a href="#extension-de-burp" id="extension-de-burp"></a>

JSON Web Token Attacker - JOSEPH

### Securización <a href="#securizacion" id="securizacion"></a>

### Recursos <a href="#recursos" id="recursos"></a>

#### Vídeos <a href="#videos" id="videos"></a>

* [Modern Webapp Pentesting: How to Attack a JWT](https://www.youtube.com/watch?v=muYmiEtPL8U).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://www.xtormin.com/pentesting-en-aplicaciones-web/general/ataques-y-vulnerabilidades/autenticacion/vulnerabilidades-jwt.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
