Cognito User Pools

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

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

基本情報

ユーザープールはAmazon Cognitoのユーザーディレクトリです。ユーザープールを使用すると、ユーザーはAmazon Cognitoを介してWebアプリやモバイルアプリにサインインしたり、サードパーティのIDプロバイダを介してフェデレーションしたりできます。ユーザーが直接サインインするか、サードパーティを介してサインインするかに関係なく、ユーザープールのすべてのメンバーには、SDKを介してアクセスできるディレクトリプロファイルがあります。

ユーザープールは以下を提供します:

  • サインアップおよびサインインサービス

  • ユーザーのサインインに使用する組み込みのカスタマイズ可能なWeb UI

  • Facebook、Google、Amazonログイン、Appleログイン、およびSAMLおよびOIDC IDプロバイダを介したソーシャルサインイン、およびユーザープールからのユーザーディレクトリ管理とユーザープロファイル

  • マルチファクタ認証(MFA)、侵害された資格情報のチェック、アカウント乗っ取り保護、電話およびメールの確認などのセキュリティ機能

  • AWS Lambdaトリガーを介したカスタマイズされたワークフローとユーザーマイグレーション

アプリケーションのソースコードには通常、Cognitoユーザープールにログインするために必要なユーザープールIDクライアントアプリケーションID(およびアプリケーションシークレット?)も含まれています。

潜在的な攻撃

  • 登録: ユーザーはデフォルトで自分自身を登録できるため、自分自身のユーザーを作成できます。

  • ユーザー列挙: 登録機能を使用して既に存在するユーザー名を見つけることができます。この情報はブルートフォース攻撃に役立ちます。

  • ログインブルートフォース: 認証セクションには、ユーザーがログインするために必要な方法がすべて記載されています。これらをブルートフォース攻撃して有効な資格情報を見つけることができます。

ペンテストツール

  • Pacuは、AWSの脆弱性フレームワークで、アカウント内のすべてのCognitoアセットの列挙を自動化し、弱い構成、アクセス制御に使用されるユーザー属性などをフラグ付けし、MFAサポートを含むユーザー作成と、変更可能なカスタム属性に基づく特権昇格、使用可能なアイデンティティプール資格情報、IDトークン内の仮定可能なロールなどを自動化します。

モジュールの機能の説明については、ブログ投稿の第2部を参照してください。インストール手順については、メインのPacuページを参照してください。

使用法

指定されたアイデンティティプールとユーザープールクライアントに対してユーザー作成とすべての特権昇格ベクトルを試行するためのcognito__attackのサンプル使用法:

Pacu (new:test) > run cognito__attack --username randomuser --email XX+sdfs2@gmail.com --identity_pools
us-east-2:a06XXXXX-c9XX-4aXX-9a33-9ceXXXXXXXXX --user_pool_clients
59f6tuhfXXXXXXXXXXXXXXXXXX@us-east-2_0aXXXXXXX

以下は、現在のAWSアカウントで表示されるすべてのユーザープール、ユーザープールクライアント、アイデンティティプール、ユーザーなどを収集するためのcognito__enumのサンプル使用方法です:

Pacu (new:test) > run cognito__enum
  • Cognito Scanner は、Cognito 上でのさまざまな攻撃、不要なアカウントの作成、アカウントオラクルを実装する Python の CLI ツールです。

インストール

$ pip install cognito-scanner

使用法

$ cognito-scanner --help

詳細については、https://github.com/padok-team/cognito-scanner を参照してください。

登録

ユーザープールは、デフォルトで新しいユーザーを登録することを許可します。

aws cognito-idp sign-up --client-id <client-id> \
--username <username> --password <password> \
--region <region> --no-sign-request

誰でも登録できる場合

ユーザーについて詳細を提供する必要があるというエラーが表示される可能性があります:

An error occurred (InvalidParameterException) when calling the SignUp operation: Attributes did not conform to the schema: address: The attribute is required

必要な詳細は、次のようなJSONで提供できます:

--user-attributes '[{"Name": "email", "Value": "carlospolop@gmail.com"}, {"Name":"gender", "Value": "M"}, {"Name": "address", "Value": "street"}, {"Name": "custom:custom_name", "Value":"supername&\"*$"}]'

あなたはこの機能を使用して、既存のユーザーを列挙することもできます。これは、その名前で既に存在するユーザーがいる場合のエラーメッセージです:

An error occurred (UsernameExistsException) when calling the SignUp operation: User already exists

前のコマンドでカスタム属性が "custom:" で始まることに注意してください。 また、登録時にはユーザーの新しいカスタム属性を作成することはできませんデフォルト属性(必須でなくても)と指定されたカスタム属性にのみ値を設定できます。

または、クライアントIDが存在するかどうかをテストするだけです。クライアントIDが存在しない場合のエラーは次のとおりです:

An error occurred (ResourceNotFoundException) when calling the SignUp operation: User pool client 3ig612gjm56p1ljls1prq2miut does not exist.

管理者のみがユーザーを登録できる場合

このエラーが発生し、ユーザーを登録または列挙することができません:

An error occurred (NotAuthorizedException) when calling the SignUp operation: SignUp is not permitted for this user pool

登録の検証

Cognitoでは、新しいユーザーを電子メールまたは電話番号で検証することができます。したがって、通常、ユーザーを作成する際には、少なくともユーザー名とパスワード、電子メールと/または電話番号が必要になります。コントロールできるものを1つ設定して、新しく作成したユーザーアカウントの検証コードを受け取るようにしてください。

aws cognito-idp confirm-sign-up --client-id <cliet_id> \
--username aasdasd2 --confirmation-code <conf_code> \
--no-sign-request --region us-east-1

同じメールアドレスや電話番号を使用できるように見える場合でも、作成したユーザーを検証する必要があるときには、Cognitoが同じ情報を使用することについて文句を言い、アカウントの検証を許可しません。

特権昇格 / 属性の更新

デフォルトでは、ユーザーは次のような方法で属性の値を変更できます:

aws cognito-idp update-user-attributes \
--region us-east-1 --no-sign-request \
--user-attributes Name=address,Value=street \
--access-token <access token>

カスタム属性の権限昇格

デフォルトでは、isAdminなどのカスタム属性が使用されている場合があります。自分の属性の値を変更できるため、値を変更して権限を昇格させることができるかもしれません!

メール/ユーザー名の変更権限昇格

ユーザーのメールアドレスと電話番号を変更できますが、アカウントが検証済みのままでも、これらの属性は未検証の状態に設定されます(再度検証する必要があります)。

メールアドレスや電話番号が検証されるまで、メールアドレスや電話番号でログインすることはできませんが、ユーザー名でログインすることはできます。 メールアドレスが変更されて検証されていない場合でも、IDトークン内の**email** フィールドに表示され、email_verified フィールドは false になりますが、アプリがそれをチェックしていない場合、他のユーザーをなりすますことができます。

さらに、name フィールドには、名前属性を変更するだけで任意の値を入力できます。アプリがそのフィールドを**email**(または他の属性)の代わりにチェックしている場合、他のユーザーをなりすますことができるかもしれません。

とにかく、たとえばメールアドレスを新しいものに変更した場合でも、そのメールアドレスに受信したコードでメールを確認できます:

aws cognito-idp verify-user-attribute \
--access-token <access_token> \
--attribute-name email --code <code> \
--region <region> --no-sign-request

**emailの代わりにphone_number**を使用して、新しい電話番号を変更/確認します。

管理者は、ユーザーが選択したユーザー名でログインするオプションを有効にすることもできます。既に使用されている任意のユーザー名またはpreferred_usernameにこの値を変更できないことに注意してください。これにより、異なるユーザーをなりすますことができます。

パスワードの回復/変更

ユーザー名(または電子メールまたは電話番号が受け入れられます)を知っているだけで、パスワードを回復することが可能で、コードがそこに送信されます。

aws cognito-idp forgot-password \
--client-id <client_id> \
--username <username/email/phone> --region <region>

サーバーの応答は常に肯定的になります。ユーザーを列挙するためにこの方法を使用することはできません。

コードを使用してパスワードを変更できます:

aws cognito-idp confirm-forgot-password \
--client-id <client_id> \
--username <username> \
--confirmation-code <conf_code> \
--password <pwd> --region <region>

パスワードを変更するには、以前のパスワードを知っている必要があります

aws cognito-idp change-password \
--previous-password <value> \
--proposed-password <value> \
--access-token <value>

認証

ユーザープールは、それに対して異なる認証方法をサポートしています。ユーザー名とパスワードを持っている場合、ログインするための異なる方法もサポートされています。 さらに、ユーザーがプールで認証されると、3種類のトークンが与えられます:IDトークンアクセストークン、およびリフレッシュトークン

  • IDトークン: 認証されたユーザーのアイデンティティに関するクレームnameemailphone_numberなど)が含まれています。IDトークンは、ユーザーをリソースサーバーやサーバーアプリケーションに認証するためにも使用できます。外部アプリケーションで使用する場合は、IDトークンの署名を検証する必要があります。

  • IDトークンは、ユーザーの属性値を含むトークンです。カスタム属性も含まれます。

  • アクセストークン: 認証されたユーザーに関するクレーム、ユーザーのグループのリスト、およびスコープのリストが含まれています。アクセストークンの目的は、ユーザープール内のユーザーのコンテキストでAPI操作を承認することです。たとえば、アクセストークンを使用して、ユーザーにユーザー属性の追加、変更、削除のアクセスを許可することができます。

  • リフレッシュトークン: リフレッシュトークンを使用すると、リフレッシュトークンが無効になるまでユーザーのために新しいIDトークンとアクセストークンを取得できます。デフォルトでは、リフレッシュトークンは、アプリケーションユーザーがユーザープールにサインインしてから30日後に期限切れになります。ユーザープール用のアプリケーションを作成するときに、アプリケーションのリフレッシュトークンの有効期限を60分から10年までの任意の値に設定できます。

ADMIN_NO_SRP_AUTH & ADMIN_USER_PASSWORD_AUTH

これはサーバーサイドの認証フローです:

  • サーバーサイドアプリは、InitiateAuthの代わりに**AdminInitiateAuth API操作を呼び出します。この操作には、cognito-idp:AdminInitiateAuthcognito-idp:AdminRespondToAuthChallenge**を含む権限を持つAWS資格情報が必要です。この操作は必要な認証パラメータを返します。

  • サーバーサイドアプリが認証パラメータを取得した後、AdminRespondToAuthChallenge API操作を呼び出します。AdminRespondToAuthChallenge API操作は、AWS資格情報を提供するときのみ成功します。

この方法はデフォルトでは有効になっていません

ログインするには、次の情報が必要です:

  • ユーザープールID

  • クライアントID

  • ユーザー名

  • パスワード

  • クライアントシークレット(アプリがシークレットを使用するように構成されている場合のみ)

この方法でログインできるようにするには、そのアプリケーションがALLOW_ADMIN_USER_PASSWORD_AUTHでログインを許可する必要があります。 さらに、この操作を実行するには、**cognito-idp:AdminInitiateAuthおよびcognito-idp:AdminRespondToAuthChallenge**の権限を持つ資格情報が必要です。

aws cognito-idp admin-initiate-auth \
--client-id <client-id> \
--auth-flow ADMIN_USER_PASSWORD_AUTH \
--region <region> \
--auth-parameters 'USERNAME=<username>,PASSWORD=<password>,SECRET_HASH=<hash_if_needed>'
--user-pool-id "<pool-id>"

# Check the python code to learn how to generate the hsecret_hash
ログインするためのコード

```python import boto3 import botocore import hmac import hashlib import base64

client_id = "" user_pool_id = "" client_secret = "" username = "" password = ""

boto_client = boto3.client('cognito-idp', region_name='us-east-1')

def get_secret_hash(username, client_id, client_secret): key = bytes(client_secret, 'utf-8') message = bytes(f'{username}{client_id}', 'utf-8') return base64.b64encode(hmac.new(key, message, digestmod=hashlib.sha256).digest()).decode()

If the Client App isn't configured to use a secret

just delete the line setting the SECRET_HASH

def login_user(username_or_alias, password, client_id, client_secret, user_pool_id): try: return boto_client.admin_initiate_auth( UserPoolId=user_pool_id, ClientId=client_id, AuthFlow='ADMIN_USER_PASSWORD_AUTH', AuthParameters={ 'USERNAME': username_or_alias, 'PASSWORD': password, 'SECRET_HASH': get_secret_hash(username_or_alias, client_id, client_secret) } ) except botocore.exceptions.ClientError as e: return e.response

print(login_user(username, password, client_id, client_secret, user_pool_id))

</details>

### USER_PASSWORD_AUTH

この方法は、別のシンプルで**伝統的なユーザー&パスワード認証**フローです。**伝統的な**認証方法を**Cognitoに移行**し、その後**無効にして**代わりに**ALLOW_USER_SRP_AUTH**方法を使用することが推奨されています(パスワードをネットワーク経由で送信しないため)。\
この**方法はデフォルトで有効になっていません**。

コード内の**前の認証方法**との主な**違い**は、**ユーザープールIDを知る必要がない**ことと、**Cognitoユーザープールで追加の権限が必要ない**ことです。

**ログイン**するには、以下が必要です:

- クライアントID
- ユーザー名
- パスワード
- クライアントシークレット(アプリがシークレットを使用するように構成されている場合のみ)

<div data-gb-custom-block data-tag="hint" data-style='info'>

この方法で**ログインできるようにするには**、そのアプリケーションがALLOW_USER_PASSWORD_AUTHでログインを許可する必要があります。

</div>

```python
aws cognito-idp initiate-auth  --client-id <client-id> \
--auth-flow USER_PASSWORD_AUTH --region <region> \
--auth-parameters 'USERNAME=<username>,PASSWORD=<password>,SECRET_HASH=<hash_if_needed>'

# Check the python code to learn how to generate the secret_hash

REFRESH_TOKEN_AUTH & REFRESH_TOKEN

このメソッドは常に有効です(無効にすることはできません)が、有効なリフレッシュトークンが必要です。

aws cognito-idp initiate-auth \
--client-id 3ig6h5gjm56p1ljls1prq2miut \
--auth-flow REFRESH_TOKEN_AUTH \
--region us-east-1 \
--auth-parameters 'REFRESH_TOKEN=<token>'

最終更新