Cognito User Pools

Apprenez le piratage AWS de zéro à héros avec htARTE (Expert en équipe rouge AWS de HackTricks)!

Autres façons de soutenir HackTricks :

Informations de base

Un pool d'utilisateurs est un répertoire d'utilisateurs dans Amazon Cognito. Avec un pool d'utilisateurs, vos utilisateurs peuvent se connecter à votre application web ou mobile via Amazon Cognito, ou fédérer via un fournisseur d'identité tiers (IdP). Que vos utilisateurs se connectent directement ou via un tiers, tous les membres du pool d'utilisateurs ont un profil de répertoire auquel vous pouvez accéder via un SDK.

Les pools d'utilisateurs offrent :

  • Services d'inscription et de connexion.

  • Une interface utilisateur web intégrée et personnalisable pour connecter les utilisateurs.

  • Connexion sociale avec Facebook, Google, Connexion avec Amazon et Connexion avec Apple, et via des fournisseurs d'identité SAML et OIDC de votre pool d'utilisateurs.

  • Gestion du répertoire des utilisateurs et profils d'utilisateurs.

  • Fonctionnalités de sécurité telles que l'authentification multi-facteurs (MFA), vérifications des informations d'identification compromises, protection contre la prise de contrôle de compte, et vérification par téléphone et e-mail.

  • Workflows personnalisés et migration des utilisateurs via des déclencheurs AWS Lambda.

Le code source des applications contiendra généralement également l'ID du pool d'utilisateurs et l'ID de l'application cliente, (et parfois le secret de l'application ?) qui sont nécessaires pour qu'un utilisateur se connecte à un Pool d'utilisateurs Cognito.

Attaques potentielles

  • Inscription : Par défaut, un utilisateur peut s'inscrire lui-même, il pourrait donc créer un utilisateur pour lui-même.

  • Énumération des utilisateurs : La fonctionnalité d'inscription peut être utilisée pour trouver des noms d'utilisateur déjà existants. Ces informations peuvent être utiles pour l'attaque par force brute.

  • Attaque par force brute de connexion : Dans la section Authentification, vous avez tous les méthodes qu'un utilisateur doit utiliser pour se connecter, vous pourriez essayer de les attaquer par force brute pour trouver des identifiants valides.

Outils pour les tests d'intrusion

  • Pacu, le framework d'exploitation AWS, inclut désormais les modules "cognito__enum" et "cognito__attack" qui automatisent l'énumération de tous les actifs Cognito dans un compte et signalent les configurations faibles, les attributs d'utilisateur utilisés pour le contrôle d'accès, etc., et automatisent également la création d'utilisateurs (y compris la prise en charge de MFA) et l'élévation de privilèges basée sur des attributs personnalisables modifiables, des informations d'identification de pool d'identités utilisables, des rôles assumables dans les jetons d'identité, etc.

Pour une description des fonctions des modules, consultez la partie 2 du billet de blog. Pour les instructions d'installation, consultez la page principale de Pacu.

Utilisation

Exemple d'utilisation de l'attaque cognito__attack pour tenter la création d'utilisateur et tous les vecteurs d'élévation de privilèges contre un pool d'identités donné et un client de pool d'utilisateurs :

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

Voici un exemple d'utilisation de cognito__enum pour rassembler tous les pools d'utilisateurs, les clients de pool d'utilisateurs, les pools d'identités, les utilisateurs, etc. visibles dans le compte AWS actuel :

Pacu (new:test) > run cognito__enum
  • Cognito Scanner est un outil CLI en python qui implémente différentes attaques sur Cognito, y compris la création de compte non désirée et l'oracle de compte.

Installation

$ pip install cognito-scanner

Utilisation

$ cognito-scanner --help

Pour plus d'informations, consultez https://github.com/padok-team/cognito-scanner

Inscription

Les pools d'utilisateurs permettent par défaut de s'inscrire de nouveaux utilisateurs.

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

Si n'importe qui peut s'inscrire

Vous pourriez rencontrer une erreur vous indiquant que vous devez fournir plus de détails sur l'utilisateur :

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

Vous pouvez fournir les détails nécessaires avec un JSON tel que :

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

Vous pourriez également utiliser cette fonctionnalité pour énumérer les utilisateurs existants. Ceci est le message d'erreur lorsqu'un utilisateur existe déjà avec ce nom :

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

Notez dans la commande précédente comment les attributs personnalisés commencent par "custom:". Sachez également qu'en vous inscrivant, vous ne pouvez pas créer de nouveaux attributs personnalisés pour l'utilisateur. Vous ne pouvez donner une valeur qu'aux attributs par défaut (même s'ils ne sont pas requis) et aux attributs personnalisés spécifiés.

Ou simplement pour tester si un ID client existe. Voici l'erreur si l'ID client n'existe pas :

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

Si seulement l'administrateur peut enregistrer des utilisateurs

Vous rencontrerez cette erreur et vous ne pourrez pas enregistrer ou énumérer les utilisateurs :

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

Vérification de l'inscription

Cognito permet de vérifier un nouvel utilisateur en vérifiant son adresse e-mail ou son numéro de téléphone. Par conséquent, lors de la création d'un utilisateur, vous devrez généralement fournir au moins le nom d'utilisateur et le mot de passe ainsi que l'adresse e-mail et/ou le numéro de téléphone. Il suffit de définir un que vous contrôlez afin de recevoir le code pour vérifier votre compte utilisateur nouvellement créé comme ceci :

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

Même si il semble que vous puissiez utiliser la même adresse e-mail et numéro de téléphone, lorsque vous devez vérifier l'utilisateur créé, Cognito se plaindra de l'utilisation des mêmes informations et ne vous permettra pas de vérifier le compte.

Élévation de privilèges / Mise à jour des attributs

Par défaut, un utilisateur peut modifier la valeur de ses attributs avec quelque chose comme :

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

Élévation de privilèges d'attribut personnalisé

Vous pourriez trouver des attributs personnalisés en cours d'utilisation (comme isAdmin), car par défaut vous pouvez modifier les valeurs de vos propres attributs, vous pourriez être en mesure d'élever les privilèges en changeant la valeur vous-même !

Élévation de privilèges par modification de l'email/nom d'utilisateur

Vous pouvez utiliser ceci pour modifier l'email et le numéro de téléphone d'un utilisateur, mais ensuite, même si le compte reste vérifié, ces attributs sont définis en statut non vérifié (vous devez les vérifier à nouveau).

Vous ne pourrez pas vous connecter avec l'email ou le numéro de téléphone tant que vous ne les aurez pas vérifiés, mais vous pourrez vous connecter avec le nom d'utilisateur. Notez que même si l'email a été modifié et n'est pas vérifié, il apparaîtra dans le jeton d'identification à l'intérieur du champ email et le champ email_verified sera faux, mais si l'application ne vérifie pas cela, vous pourriez vous faire passer pour d'autres utilisateurs.

De plus, notez que vous pouvez mettre n'importe quoi à l'intérieur du champ name en modifiant simplement l'attribut de nom. Si une application vérifie ce champ pour une raison quelconque au lieu de l'email (ou tout autre attribut), vous pourriez être en mesure de vous faire passer pour d'autres utilisateurs.

Quoi qu'il en soit, si pour une raison quelconque vous avez changé votre email par exemple pour un nouveau, vous pouvez y accéder en confirmant l'email avec le code reçu dans cette adresse email :

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

Utilisez phone_number au lieu de email pour changer/vérifier un nouveau numéro de téléphone.

L'administrateur pourrait également activer l'option de connexion avec un nom d'utilisateur préféré par l'utilisateur. Notez que vous ne pourrez pas changer cette valeur en un nom d'utilisateur ou un preferred_username déjà utilisé pour se faire passer pour un utilisateur différent.

Récupérer/Changer le mot de passe

Il est possible de récupérer un mot de passe en connaissant le nom d'utilisateur (ou l'email ou le téléphone est accepté) et en y ayant accès, un code y sera envoyé :

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

La réponse du serveur sera toujours positive, comme si le nom d'utilisateur existait. Vous ne pouvez pas utiliser cette méthode pour énumérer les utilisateurs.

Avec le code, vous pouvez changer le mot de passe avec :

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

Pour changer le mot de passe, vous devez connaître le mot de passe précédent :

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

Authentification

Un pool d'utilisateurs prend en charge différentes façons de s'authentifier. Si vous avez un nom d'utilisateur et un mot de passe, il existe également différentes méthodes prises en charge pour se connecter. De plus, lorsqu'un utilisateur est authentifié dans le Pool, 3 types de jetons sont donnés : Le jeton ID, le jeton d'accès et le jeton de rafraîchissement.

  • Jeton ID : Il contient des revendications sur l'identité de l'utilisateur authentifié, telles que nom, email et numéro de téléphone. Le jeton ID peut également être utilisé pour authentifier les utilisateurs auprès de vos serveurs de ressources ou applications serveur. Vous devez vérifier la signature du jeton ID avant de pouvoir faire confiance à toutes les revendications à l'intérieur du jeton ID si vous l'utilisez dans des applications externes.

  • Le jeton ID est le jeton qui contient les valeurs des attributs de l'utilisateur, même les personnalisés.

  • Jeton d'accès : Il contient des revendications sur l'utilisateur authentifié, une liste des groupes de l'utilisateur et une liste de portées. Le but du jeton d'accès est d'autoriser les opérations API dans le contexte de l'utilisateur dans le pool d'utilisateurs. Par exemple, vous pouvez utiliser le jeton d'accès pour accorder à votre utilisateur l'accès pour ajouter, modifier ou supprimer des attributs d'utilisateur.

  • Jeton de rafraîchissement : Avec les jetons de rafraîchissement, vous pouvez obtenir de nouveaux jetons ID et d'accès pour l'utilisateur jusqu'à ce que le jeton de rafraîchissement soit invalide. Par défaut, le jeton de rafraîchissement expire 30 jours après que votre utilisateur d'application se connecte à votre pool d'utilisateurs. Lorsque vous créez une application pour votre pool d'utilisateurs, vous pouvez définir l'expiration du jeton de rafraîchissement de l'application à n'importe quelle valeur entre 60 minutes et 10 ans.

ADMIN_NO_SRP_AUTH & ADMIN_USER_PASSWORD_AUTH

Il s'agit du flux d'authentification côté serveur :

  • L'application côté serveur appelle l'opération API AdminInitiateAuth (au lieu de InitiateAuth). Cette opération nécessite des informations d'identification AWS avec des autorisations incluant cognito-idp:AdminInitiateAuth et cognito-idp:AdminRespondToAuthChallenge. L'opération renvoie les paramètres d'authentification requis.

  • Après que l'application côté serveur ait les paramètres d'authentification, elle appelle l'opération API AdminRespondToAuthChallenge. L'opération AdminRespondToAuthChallenge réussit uniquement lorsque vous fournissez des informations d'identification AWS.

Cette méthode n'est PAS activée par défaut.

Pour se connecter, vous devez connaître :

  • l'ID du pool d'utilisateurs

  • l'ID client

  • le nom d'utilisateur

  • le mot de passe

  • le secret client (uniquement si l'application est configurée pour utiliser un secret)

Afin de pouvoir vous connecter avec cette méthode, l'application doit autoriser la connexion avec ALLOW_ADMIN_USER_PASSWORD_AUTH. De plus, pour effectuer cette action, vous avez besoin d'informations d'identification avec les autorisations cognito-idp:AdminInitiateAuth et 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
Code pour se connecter

```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>

### AUTHENTIFICATION_PAR_MOT_DE_PASSE_UTILISATEUR

Cette méthode est un autre flux d'authentification simple et **traditionnel utilisateur & mot de passe**. Il est recommandé de **migrer une méthode d'authentification traditionnelle** vers Cognito et **recommandé** de **la désactiver** puis d'utiliser la méthode **ALLOW\_USER\_SRP\_AUTH** à la place (car celle-ci ne transmet jamais le mot de passe sur le réseau).\
Cette **méthode n'est PAS activée** par défaut.

La principale **différence** avec la **méthode d'authentification précédente** dans le code est que vous **n'avez pas besoin de connaître l'ID du pool d'utilisateurs** et que vous **n'avez pas besoin de permissions supplémentaires** dans le pool d'utilisateurs Cognito.

Pour **vous connecter**, vous **devez** connaître :

* l'identifiant du client
* le nom d'utilisateur
* le mot de passe
* le secret du client (uniquement si l'application est configurée pour utiliser un secret)

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

Pour **pouvoir vous connecter avec cette méthode**, l'application doit autoriser la connexion avec 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

AUTH_PAR_JETON_DE_RAFRAÎCHISSEMENT & JETON_DE_RAFRAÎCHISSEMENT

Cette méthode sera toujours valide (elle ne peut pas être désactivée) mais vous devez avoir un jeton de rafraîchissement valide.

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

Dernière mise à jour