hacktricks/pentesting-web/oauth-to-account-takeover.md

32 KiB
Raw Blame History

OAuthを使ったアカウント乗っ取り

AWSハッキングをゼロからヒーローまで学ぶには htARTE (HackTricks AWS Red Team Expert)をチェック!

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

基本情報

OAuthにはいくつかの異なるバージョンがあります。基本的な理解を得るためにhttps://oauth.net/2/を読むことができます。

この記事では、今日最も一般的に遭遇するフローであるOAuth 2.0認可コードグラントタイプに焦点を当てます。本質的に、OAuthは開発者に別のアプリケーション(認可サーバー)からあなたのアカウントのデータにアクセスしたり、特定のアクションを実行するための認可メカニズムを提供します。

例えば、https://yourtweetreader.comあなたが今までに送った全てのツイートを表示する機能を持っているとしましょう。これにはOAuth 2.0が導入されています。https://yourtweetreader.comあなたのツイートにアクセスするためにTwitterアプリケーションの認可を求めますhttps://twitter.com に同意ページが表示され、どの権限が要求されているか、そしてそれを要求している開発者が誰かが表示されます。あなたが要求を認可すると、https://yourtweetreader.comあなたに代わってあなたのツイートにアクセスすることができるようになります。

OAuth 2.0のコンテキストで理解する重要な要素:

  • リソースオーナー: リソースオーナーは、Twitterアカウントのツイートなど、保護されたリソースへのアクセスを許可するユーザー/エンティティです。この例では、これはあなたです。
  • リソースサーバー: リソースサーバーは、アプリケーションがアクセストークンを取得した後に認証されたリクエストを処理するサーバーです。この例では、これはhttps://twitter.comです。
  • クライアントアプリケーション: クライアントアプリケーションは、リソースオーナーから認可を要求するアプリケーションです。この例では、これはhttps://yourtweetreader.comです。
  • 認可サーバー: 認可サーバーは、リソースオーナーを正常に認証し、認可を取得した後にクライアントアプリケーションアクセストークンを発行するサーバーです。上記の例では、これはhttps://twitter.comです。
  • client_id: client_idアプリケーションの識別子です。これは公開されている、非秘密の一意の識別子です。
  • client_secret: client_secretアプリケーションと認可サーバーのみが知っている秘密です。これはアクセストークンを生成するために使用されます。
  • response_type: response_typeは、要求されているトークンのタイプを詳細に説明する値です。例えばcodeなどです。
  • scope: scopeクライアントアプリケーションリソースオーナーから要求しているアクセスレベルです。
  • redirect_uri: redirect_uriは、認可が完了した後にユーザーがリダイレクトされるURLです。これは通常、以前にサービスに登録したリダイレクトURLと一致する必要があります。
  • state: stateパラメータは、ユーザーが認可サーバーにリダイレクトされてから再び戻ってくる間にデータを保持することができます。これはリクエストごとに一意またはランダムな値を含む場合、CSRF保護メカニズムとして機能するため、一意の値であることが重要です。
  • grant_type: grant_typeパラメータは、グラントタイプが何であるか、どのトークンが返されるかを説明します。
  • code: このcodeは、このリクエストのクエリ文字列パラメータ「code」にある認可サーバーから受け取った認可コードです。このコードはクライアントアプリケーションアクセストークンを取得するためにclient_idclient_secretと共に使用されます。
  • access_token: access_tokenは、クライアントアプリケーションリソースオーナーを代表してAPIリクエストを行うために使用するトークンです。
  • refresh_token: refresh_tokenは、アプリケーションがユーザーにプロンプトを表示せずに新しいアクセストークンを取得することを可能にします。

実際の例

これらを全てまとめると、実際のOAuthフローは以下のようになります:

  1. https://yourtweetreader.comを訪れ、「Twitterと連携する」ボタンをクリックします。
  2. https://yourtweetreader.comhttps://twitter.comにリクエストを送り、リソースオーナーであるあなたに、https://yourtweetreader.comのTwitterアプリケーションがあなたのツイートにアクセスすることを認可するよう求めます。リクエストは次のようになります
https://twitter.com/auth
?response_type=code
&client_id=yourtweetreader_clientId
&redirect_uri=https%3A%2F%2Fyourtweetreader.com%2Fcallback
&scope=readTweets
&state=kasodk9d1jd992k9klaskdh123

3. 同意ページが表示されます:

4. 同意すると、Twitterはredirect_uricodestateパラメータを含むリクエストを送り返します:

https://yourtweetreader.com?code=asd91j3jd91j92j1j9d1&state=kasodk9d1jd992k9klaskdh123

5. https://yourtweetreader.com はその code を取得し、アプリケーションの client_idclient_secret を使用して、サーバーから access_token を取得するリクエストを行います。これにより、あなたが同意した権限にアクセスできるようになります:

POST /oauth/access_token
Host: twitter.com
...{"client_id": "yourtweetreader_clientId", "client_secret": "yourtweetreader_clientSecret", "code": "asd91j3jd91j92j1j9d1", "grant_type": "authorization_code"}

6. 最終的に、フローが完了し、https://yourtweetreader.com はあなたの access_token を使って Twitter の API を呼び出し、あなたのツイートにアクセスします。

バグバウンティの発見

さて、興味深い部分ですOAuth 実装には多くの問題が発生する可能性があり、ここでは私が頻繁に見かけるバグの異なるカテゴリーを紹介します:

弱い redirect_uri 設定

redirect_uri は非常に重要です。なぜなら、機密データである code が認証後にこの URL に追加されるからです。もし redirect_uri攻撃者が制御するサーバー にリダイレクトされる場合、攻撃者は code を自分で使用し、被害者のデータにアクセスすることで、被害者のアカウントを乗っ取る 可能性があります。

この脆弱性をどのように悪用するかは、認証サーバーによって異なります。一部のサーバーは クライアントアプリケーションで指定された redirect_uri パスと全く同じもののみを受け入れますが、他のサーバーは redirect_uri の同じドメインやサブディレクトリ内のものなら 何でも受け入れます

サーバーが扱うロジックによっては、redirect_uri をバイパスするためのいくつかのテクニックがあります。redirect_urihttps://yourtweetreader.com/callback の場合、これには以下が含まれます:

  • オープンリダイレクト: https://yourtweetreader.com/callback?redirectUrl=https://evil.com
  • パストラバーサル: https://yourtweetreader.com/callback/../redirect?url=https://evil.com
  • 弱い redirect_uri 正規表現: https://yourtweetreader.com.evil.com
  • HTML インジェクションと referer ヘッダーを介したトークンの盗難: https://yourtweetreader.com/callback/home/attackerimg.jpg

オープンリダイレクトに脆弱な他のパラメーターには以下があります:

  • client_uri - クライアントアプリケーションのホームページの URL
  • policy_uri - エンドユーザーが自分のプロファイルデータの使用方法について読むことができるように、クライアントアプリケーションが提供する URL。
  • tos_uri - エンドユーザーが利用規約について読むことができるように、クライアントが提供する URL。
  • initiate_login_uri - 第三者が RP によるログインを開始するために使用できる https スキームの URI。クライアント側のリダイレクションにも使用されるべきです。

これらのパラメーターは OAuth および OpenID の仕様によると オプションであり、特定のサーバーでは常にサポートされているわけではないので、サーバーでどのパラメーターがサポートされているかを特定することが常に価値があります。

OpenID サーバーを対象とする場合、**.well-known/openid-configuration** の発見エンドポイントには、"registration_endpoint"、"request_uri_parameter_supported"、"require_request_uri_registration" などのパラメーターが含まれることがあります。これらは、登録エンドポイントや他のサーバー構成値を見つけるのに役立ちます。

リダイレクト実装における XSS

このバグバウンティレポート https://blog.dixitaditya.com/2021/11/19/account-takeover-chain.html で述べられているように、ユーザーが認証した後にサーバーのレスポンスでリダイレクト URL が反映されている 可能性があり、XSS に脆弱 です。テストする可能性のあるペイロード:

https://app.victim.com/login?redirectUrl=https://app.victim.com/dashboard</script><h1>test</h1>

CSRF - 状態パラメータの不適切な取り扱い

非常に多くの場合、state パラメータは完全に省略されているか、間違った方法で使用されています。もし状態パラメータが 存在しないまたは変化しない静的な値であれば、OAuthフローは非常に高い確率で CSRFに対して脆弱 になります。時には、state パラメータが存在しても、アプリケーションがパラメータの検証を全く行わないことがあり、攻撃が成功する可能性があります。この脆弱性を利用する方法は、自分のアカウントで認証プロセスを行い、認証直後に一時停止することです。すると、次のようなリクエストに遭遇します:

https://yourtweetreader.com?code=asd91j3jd91j92j1j9d1

このリクエストを受け取った後、これらのコードは通常一度限りの使用なので、リクエストをドロップすることができます。その後、このURLをログイン済みのユーザーに送信し、あなたのアカウントをそのユーザーのアカウントに追加することができます。最初は、単にあなたのアカウントを被害者のアカウントに追加しているだけなので、それほど敏感に聞こえないかもしれません。しかし、多くのOAuth実装はサインイン目的で使用されているため、ログインに使用されるGoogleアカウントを追加できれば、クリック一つでアカウント乗っ取りを実行し、Googleアカウントでログインすることで被害者のアカウントにアクセスできる可能性があります。

この件についてのは、このCTF writeupHTB box called Oouchで見ることができます。

また、stateパラメータが追加のリダイレクト値として使用されることも何度か見かけました。アプリケーションは初期リダイレクトにredirect_uriを使用しますが、その後、クエリパラメータ内にcodeを含むか、refererヘッダーを参照する可能性のある2回目のリダイレクトにstateパラメータを使用します。

重要な点は、これがログインやアカウント乗っ取りタイプの状況にのみ適用されるわけではないということです。私が見た設定ミスには以下のようなものがあります:

  • Slackの統合により、攻撃者がすべての通知/メッセージの受信者として自分のSlackアカウントを追加できる
  • Stripeの統合により、攻撃者が支払い情報を上書きし、被害者の顧客からの支払いを受け取ることができる
  • PayPalの統合により、攻撃者が自分のPayPalアカウントを被害者のアカウントに追加でき、攻撃者のPayPalにお金が入金される

アカウント乗っ取り前

私がよく見る問題の1つは、アプリケーションが「Xでサインイン」を許可する一方で、ユーザー名/パスワードも使用できる場合です。これには2つの異なる攻撃方法があります

  1. アプリケーションがアカウント作成時にメール確認を要求しない場合、被害者が登録する前に被害者のメールアドレスと攻撃者のパスワードを使用してアカウントを作成してみてください。その後、被害者がGoogleなどの第三者を使用して登録またはサインインしようとすると、アプリケーションがルックアップを行い、そのメールアドレスがすでに登録されていることを確認し、攻撃者が作成したアカウントに被害者のGoogleアカウントをリンクする可能性があります。これは、攻撃者が被害者が登録する前にアカウントを作成した場合に、被害者のアカウントにアクセスできる「アカウント乗っ取り前」の状況です。
  2. OAuthアプリがメール確認を要求しない場合、そのOAuthアプリでサインアップし、その後、被害者のメールアドレスにメールアドレスを変更してみてください。上記と同じ問題が存在する可能性がありますが、逆の方向から攻撃して、アカウント乗っ取りのために被害者のアカウントにアクセスします。

シークレットの開示

OAuthパラメータの中でどれが秘密であるかを認識し、それらを保護することが非常に重要です。例えば、client_idの漏洩は完全に問題なく、必要ですが、client_secretの漏洩は危険です。これが漏洩すると、攻撃者は信頼されたクライアントアプリケーションの信頼とアイデンティティを悪用して、統合されたアカウントのユーザーaccess_tokensやプライベート情報/アクセスを盗む可能性があります。先ほどの例に戻ると、私が見た問題の1つは、このステップをサーバーではなくクライアントから実行することです

5. https://yourtweetreader.com はそのcodeを取得し、アプリケーションのclient_idclient_secretを使用して、あなたに代わってaccess_tokenを取得するためにサーバーからリクエストを行います。これにより、あなたが同意した権限にアクセスできます。

これがクライアントから行われる場合、client_secretが漏洩し、ユーザーはアプリケーションを代表してaccess_tokensを生成することができます。いくつかのソーシャルエンジニアリングを行うことで、OAuth認証にさらにスコープを追加することもでき、信頼されたクライアントアプリケーションからのリクエストとしてすべてが正当に見えます。

クライアントシークレットのブルートフォース

サービスプロバイダのclient_secretをアイデンティティプロバイダとともにブルートフォースすることを試みることができます。これにより、アカウントを盗むことを試みることができます。 BFへのリクエストは以下のようになるかもしれません

POST /token HTTP/1.1
content-type: application/x-www-form-urlencoded
host: 10.10.10.10:3000
content-length: 135
Connection: close

code=77515&redirect_uri=http%3A%2F%2F10.10.10.10%3A3000%2Fcallback&grant_type=authorization_code&client_id=public_client_id&client_secret=[bruteforce]

Referer ヘッダーによる Code + State の漏洩

クライアントが code と state を持っている場合、別のページに移動する際にそれが Referer ヘッダー内で反映されている と、脆弱性があると言えます。

ブラウザ履歴に保存されたアクセストークン

ブラウザの履歴を確認し、アクセストークンが保存されているかをチェックしてください

永続的な認可コード

認可コードは一定時間のみ有効であるべきです。攻撃者が盗み、使用する時間窓を限定するためです

クライアントに紐づいていない認可/リフレッシュトークン

異なるクライアントで 認可コードを取得し、使用できる場合、他のアカウントの乗っ取りが可能です

Happy Paths, XSS, Iframes & Post Messages を利用した code & state 値の漏洩

AWS Cognito

このバグバウンティレポート: https://security.lauritz-holtmann.de/advisories/flickr-account-takeover/ では、AWS Cognito がユーザーに返す トークン が、ユーザーデータを上書きするのに 十分な権限を持っている 可能性があることがわかります。したがって、異なるユーザーのメールアドレスに ユーザーのメールを変更できる 場合、他のアカウントの 乗っ取り が可能になるかもしれません。

# Read info of the user
aws cognito-idp get-user --region us-east-1 --access-token eyJraWQiOiJPVj[...]

# Change email address
aws cognito-idp update-user-attributes --region us-east-1 --access-token eyJraWQ[...] --user-attributes Name=email,Value=imaginary@flickr.com
{
"CodeDeliveryDetailsList": [
{
"Destination": "i***@f***.com",
"DeliveryMedium": "EMAIL",
"AttributeName": "email"
}
]
}

AWS cognitoの悪用方法についての詳細は、以下をチェックしてください

{% embed url="https://cloud.hacktricks.xyz/pentesting-cloud/aws-pentesting/aws-unauthenticated-enum-access/aws-cognito-unauthenticated-enum" %}

他のアプリのトークンを悪用する

このライトアップで述べられているようにトークンを受け取ることを期待しているOAuthフローは、そのトークンがアプリに属しているかどうかをチェックしていない場合、脆弱性を持つ可能性があります。

これは、攻撃者がOAuthをサポートするアプリケーションを作成し、Facebookでログインする(例えば)ことができるためです。その後、被害者が攻撃者のアプリケーションでFacebookでログインすると、攻撃者は自分のアプリケーションに与えられたユーザーのOAuthトークンを取得し、被害者のOAuthアプリケーションで被害者のユーザートークンを使用してログインすることができます

{% hint style="danger" %} したがって、攻撃者がユーザーに自分のOAuthアプリケーションを使用させることに成功した場合、トークンを期待していて、そのトークンが自分たちのアプリIDに付与されたものかどうかをチェックしていないアプリケーションで、被害者のアカウントを乗っ取ることができます。 {% endhint %}

二つのリンクとクッキー

このライトアップによると、攻撃者のホストを指すreturnUrlを含むページを被害者に開かせることが可能でした。この情報はクッキーRUに保存され後のステッププロンプトユーザーにその攻撃者のホストへのアクセスを許可するかどうかを尋ねます

このプロンプトをバイパスするために、returnUrlを使用してこのRUクッキーを設定するOauthフローを開始するタブを開き、プロンプトが表示される前にタブを閉じ、その値なしで新しいタブを開くことが可能でした。その結果、プロンプトは攻撃者のホストについて通知しませんが、クッキーはそれに設定されているため、トークンはリダイレクションで攻撃者のホストに送信されます

SSRFsパラメータ

見逃してしまうかもしれない隠されたURLの一つは、Dynamic Client Registrationエンドポイントです。ユーザーを正常に認証するために、OAuthサーバーはクライアントアプリケーションに関する詳細を知る必要があります。例えば"client_name"、"client_secret"、"redirect_uris"などです。これらの詳細はローカル設定を介して提供されることもありますが、OAuth認証サーバーには特別な登録エンドポイントも存在することがあります。このエンドポイントは通常"/register"にマッピングされ、以下の形式のPOSTリクエストを受け付けます

POST /connect/register HTTP/1.1
Content-Type: application/json
Host: server.example.com
Authorization: Bearer eyJhbGciOiJSUzI1NiJ9.eyJ ...

{
"application_type": "web",
"redirect_uris": ["https://client.example.org/callback"],
"client_name": "My Example",
"logo_uri": "https://client.example.org/logo.png",
"subject_type": "pairwise",
"sector_identifier_uri": "https://example.org/rdrct_uris.json",
"token_endpoint_auth_method": "client_secret_basic",
"jwks_uri": "https://client.example.org/public_keys.jwks",
"contacts": ["ve7jtb@example.org"],
"request_uris": ["https://client.example.org/rf.txt"]
}

このリクエストで定義されるパラメーターには、OAuth用のRFC7591Openid Connect Registration 1.0の2つの仕様があります。

ここで見ることができるように、これらの値の多くはURL参照を介して渡され、Server Side Request Forgeryの潜在的なターゲットのように見えます。同時に、私たちがテストしたほとんどのサーバーは、登録リクエストを受け取ったときにこれらのURLをすぐに解決しません。代わりに、これらのパラメーターを保存し、OAuth認証フロー中に後で使用します。言い換えれば、これはより二次的なSSRFであり、ブラックボックス検出を困難にします。

以下のパラメーターはSSRF攻撃に特に興味深いです

  • logo_uri - クライアントアプリケーションのロゴを参照するURLクライアントを登録した後、新しい"client_id"を使用してOAuth認証エンドポイント("/authorize")を呼び出すことができます。ログイン後、サーバーはリクエストを承認するように求め、"logo_uri"から画像を表示する可能性がありますサーバーが自身で画像を取得する場合、SSRFはこのステップでトリガーされるはずです。代わりに、サーバーはクライアント側の""タグを介してロゴを含めるかもしれません。これはSSRFにはつながりませんが、URLがエスケープされていない場合はXSSにつながる可能性があります
  • jwks_uri - クライアントのJSON Web Key Set [JWK]ドキュメントのURL。このキーセットは、JWTをクライアント認証に使用するときにトークンエンドポイントへの署名付きリクエストを検証するためにサーバー上で必要です [RFC7523]。このパラメーターでSSRFをテストするために、悪意のある"jwks_uri"を持つ新しいクライアントアプリケーションを登録し任意のユーザーの認証コードを取得するために認証プロセスを実行し、次のボディを持つ"/token"エンドポイントをフェッチします

POST /oauth/token HTTP/1.1
...
``
grant_type=authorization_code&code=n0esc3NRze7LTCu7iYzS6a5acc3f0ogp4&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&client_assertion=eyJhbGci...

脆弱であれば、サーバーは提供された"jwks_uri"へのサーバー間HTTPリクエストを実行するはずです。なぜなら、リクエスト内の"client_assertion"パラメーターの妥当性をチェックするためにこのキーが必要だからです。これはおそらくブラインドSSRFの脆弱性になるでしょう。サーバーは適切なJSONレスポンスを期待しています。

  • sector_identifier_uri - redirect_uri値のJSON配列を参照するファイルのURLです。サポートされている場合、サーバーは動的登録リクエストを提出するとすぐにこの値をフェッチする可能性があります。すぐにフェッチされない場合は、このクライアントに対してサーバーで認証を実行してみてください。認証フローを完了するためにredirect_urisを知る必要があるため、これによりサーバーは悪意のあるsector_identifier_uriへのリクエストを強制されます。
  • request_uris - このクライアントの許可されたrequest_urisの配列です。"request_uri"パラメーターは、リクエスト情報を含むJWTを含むURLを提供するために認証エンドポイントでサポートされている可能性がありますhttps://openid.net/specs/openid-connect-core-1_0.html#rfc.section.6.2を参照)。

動的クライアント登録が有効でない場合、または認証が必要な場合でも、単に"request_uri"を使用して認証エンドポイントでSSRFを実行しようとすることができます\

GET /authorize?response_type=code%20id_token&client_id=sclient1&request_uri=https://ybd1rc7ylpbqzygoahtjh6v0frlh96.burpcollaborator.net/request.jwt

注:このパラメーターを"redirect_uri"と混同しないでください。"redirect_uri"は認証後のリダイレクトに使用されますが、"request_uri"は認証プロセスの開始時にサーバーによってフェッチされます

同時に、私たちが見た多くのサーバーは任意の"request_uri"値を許可しません事前にクライアント登録プロセス中に登録されたホワイトリストされたURLのみを許可します。そのため、事前に"request_uris": "https://ybd1rc7ylpbqzygoahtjh6v0frlh96.burpcollaborator.net/request.jwt"を提供する必要があります。

OAuthプロバイダーのレースコンディション

テストしているプラットフォームがOAuthプロバイダーである場合は、レースコンディションの可能性をテストするためにこれを読んでください

参考文献

htARTE (HackTricks AWS Red Team Expert)でAWSハッキングをゼロからヒーローまで学ぶ

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