
Proof-of-Concept (PoC) per una vulnerabilità di bypass dell'autenticazione che interessa le applicazioni che utilizzano pac4j-jwt con JWE (JSON Web Encryption).
Disclaimer: Questo exploit è stato sviluppato esclusivamente per la macchina ritirata di HackTheBox "Principal". Solo a scopo educativo. Non utilizzarlo contro sistemi che non possiedi o per i quali non hai esplicita autorizzazione al test.
| Campo | Dettagli |
|---|
| Nome | Principal |
| Piattaforma | HackTheBox |
| Difficoltà | — |
| Stato | Ritirata |
Libreria interessata: pac4j-jwt < 4.5.9 / 5.7.9 / 6.3.3
Gravità: Critica
Tipo: Bypass dell'autenticazione
Un difetto logico in JwtAuthenticator consente a un attaccante di bypassare l'autenticazione
avvolgendo un PlainJWT non firmato (alg=none) all'interno di un JWE (JWT cifrato).
Quando il server decifra il JWE, tenta di analizzare il token interno come un
SignedJWT. Poiché il token interno è un PlainJWT, l'oggetto SignedJWT è
nullo e la verifica della firma viene completamente saltata. Il server costruisce quindi un
profilo utente a partire dalle claim non verificate — consentendo la completa impersonificazione di qualsiasi
utente, inclusi gli amministratori.
Crea claim malevole (sub=admin, role=ROLE_ADMIN)
↓
Costruisci PlainJWT non firmato (alg=none)
↓
Avvolgi PlainJWT dentro un JWE usando la chiave pubblica RSA del server
↓
Invia il token JWE al server
↓
Il server decifra il JWE → trova PlainJWT → salta il controllo della firma → concede l'accesso
Vedi exploit.py
Aggiorna pac4j-jwt a una versione corretta:
4.5.9 o successiva5.7.9 o successiva6.3.3 o successivaOppure rifiuta esplicitamente i token interni PlainJWT dopo la decifratura del JWE:
if (jwt instanceof PlainJWT) {
throw new CredentialsException("PlainJWT non consentito dentro JWE");
}
/api/auth/jwks
alg: noneAvvolgi dentro un JWE usando la chiave pubblica
Invia come:
Authorization: Bearer <token>
pip install jwcrypto requests
python3 poc.py \
--jwks-url http://target/api/auth/jwks \
--target http://target/api/dashboard
[+] Token Forgiato:
eyJhbGciOiJSU0EtT0FFUC0yNTYi...
[+] Iniezione nel Browser:
sessionStorage.setItem("auth_token", "eyJhbGciOiJSU0EtT0FFUC0yNTYi...")
[+] Stato: 200
{"user":{"username":"admin","role":"ROLE_ADMIN"}}
Apri DevTools → Console:
sessionStorage.setItem("auth_token", "<PASTE_TOKEN_HERE>")
Poi naviga verso:
/dashboard
alg: none