Cognito User Pools

Aprende hacking en AWS desde cero hasta experto con htARTE (HackTricks AWS Red Team Expert)!

Otras formas de apoyar a HackTricks:

Información básica

Una piscina de usuarios es un directorio de usuarios en Amazon Cognito. Con una piscina de usuarios, tus usuarios pueden iniciar sesión en tu aplicación web o móvil a través de Amazon Cognito, o federarse a través de un proveedor de identidad de terceros (IdP). Ya sea que tus usuarios inicien sesión directamente o a través de un tercero, todos los miembros de la piscina de usuarios tienen un perfil de directorio al que puedes acceder a través de un SDK.

Las piscinas de usuarios proporcionan:

  • Servicios de registro e inicio de sesión.

  • Una interfaz web integrada y personalizable para que los usuarios inicien sesión.

  • Inicio de sesión social con Facebook, Google, Iniciar sesión con Amazon y Iniciar sesión con Apple, y a través de proveedores de identidad SAML y OIDC de tu piscina de usuarios.

  • Gestión de directorios de usuarios y perfiles de usuarios.

  • Funciones de seguridad como autenticación multifactor (MFA), verificaciones de credenciales comprometidas, protección contra toma de cuentas, y verificación de teléfono y correo electrónico.

  • Flujos de trabajo personalizados y migración de usuarios a través de desencadenadores de AWS Lambda.

El código fuente de las aplicaciones generalmente también contendrá el ID de la piscina de usuarios y el ID de la aplicación cliente, (¿y a veces el secreto de la aplicación?) que se necesitan para que un usuario inicie sesión en una Piscina de usuarios de Cognito.

Ataques potenciales

  • Registro: Por defecto, un usuario puede registrarse, por lo que podría crear un usuario para sí mismo.

  • Enumeración de usuarios: La funcionalidad de registro se puede utilizar para encontrar nombres de usuario que ya existen. Esta información puede ser útil para el ataque de fuerza bruta.

  • Fuerza bruta de inicio de sesión: En la sección de Autenticación tienes todos los métodos que un usuario tiene para iniciar sesión, podrías intentar hacer fuerza bruta para encontrar credenciales válidas.

Herramientas para pentesting

  • Pacu, el marco de explotación de AWS, ahora incluye los módulos "cognito__enum" y "cognito__attack" que automatizan la enumeración de todos los activos de Cognito en una cuenta y señalan configuraciones débiles, atributos de usuario utilizados para el control de acceso, etc., y también automatizan la creación de usuarios (incluido el soporte de MFA) y la escalada de privilegios basada en atributos personalizables modificables, credenciales de grupo de identidad utilizables, roles asumibles en tokens de identidad, etc.

Para una descripción de las funciones de los módulos, consulta la parte 2 de la publicación del blog. Para instrucciones de instalación, consulta la página principal de Pacu.

Uso

Uso de ataque cognito__attack de muestra para intentar la creación de usuarios y todos los vectores de escalada de privilegios contra un grupo de identidad y cliente de piscina de usuarios dados:

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

Ejemplo de uso de cognito__enum para recopilar todos los grupos de usuarios, clientes de grupos de usuarios, grupos de identidades, usuarios, etc. visibles en la cuenta actual de AWS:

Pacu (new:test) > run cognito__enum
  • Cognito Scanner es una herramienta de línea de comandos en python que implementa diferentes ataques en Cognito, incluyendo la creación no deseada de cuentas y el oráculo de cuentas.

Instalación

$ pip install cognito-scanner

Uso

$ cognito-scanner --help

Para obtener más información, visita https://github.com/padok-team/cognito-scanner

Registro

Los Grupos de Usuarios permiten, de forma predeterminada, registrarse a nuevos usuarios.

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

Si cualquiera puede registrarse

Podrías encontrar un error que te indique que necesitas proporcionar más detalles sobre el usuario:

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

Puedes proporcionar los detalles necesarios con un JSON como:

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

Puedes usar esta funcionalidad también para enumerar usuarios existentes. Este es el mensaje de error cuando un usuario ya existe con ese nombre:

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

Nota en el comando anterior cómo los atributos personalizados comienzan con "custom:". También ten en cuenta que al registrarte no puedes crear nuevos atributos personalizados para el usuario. Solo puedes dar valor a los atributos predeterminados (incluso si no son obligatorios) y a los atributos personalizados especificados.

O simplemente para probar si existe un ID de cliente. Este es el error si el ID de cliente no existe:

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

Si solo el administrador puede registrar usuarios

Encontrarás este error y no podrás registrar o enumerar usuarios:

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

Verificación de Registro

Cognito permite verificar a un nuevo usuario verificando su correo electrónico o número de teléfono. Por lo tanto, al crear un usuario generalmente se requerirá al menos el nombre de usuario y la contraseña y el correo electrónico y/o número de teléfono. Simplemente establezca uno que controle para que reciba el código para verificar su cuenta de usuario recién creada como se muestra a continuación:

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

Incluso si parece que puedes usar el mismo correo electrónico y número de teléfono, cuando necesites verificar el usuario creado, Cognito se quejará de usar la misma información y no te permitirá verificar la cuenta.

Escalada de privilegios / Actualización de atributos

Por defecto, un usuario puede modificar el valor de sus atributos con algo como:

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

Elevación de privilegios de atributos personalizados

Es posible que encuentres atributos personalizados en uso (como isAdmin), ya que de forma predeterminada puedes cambiar los valores de tus propios atributos, podrías elevar privilegios ¡cambiando el valor tú mismo!

Elevación de privilegios al modificar correo electrónico/nombre de usuario

Puedes usar esto para modificar el correo electrónico y el número de teléfono de un usuario, pero luego, incluso si la cuenta sigue verificada, esos atributos se establecen en estado no verificado (debes verificarlos nuevamente).

No podrás iniciar sesión con el correo electrónico o el número de teléfono hasta que los verifiques, pero podrás iniciar sesión con el nombre de usuario. Ten en cuenta que incluso si el correo electrónico fue modificado y no verificado, aparecerá en el Token de ID dentro del campo email y el campo email_verified será falso, pero si la aplicación no verifica eso, podrías suplantar a otros usuarios.

Además, ten en cuenta que puedes poner cualquier cosa dentro del campo name simplemente modificando el atributo de nombre. Si una aplicación está verificando ese campo por alguna razón en lugar del email (u otro atributo), podrías suplantar a otros usuarios.

De todos modos, si por alguna razón cambiaste tu correo electrónico, por ejemplo, a uno nuevo al que puedes acceder, puedes confirmar el correo electrónico con el código que recibiste en esa dirección de correo electrónico:

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

Utiliza phone_number en lugar de email para cambiar/verificar un nuevo número de teléfono.

El administrador también podría habilitar la opción de iniciar sesión con un nombre de usuario preferido por el usuario. Ten en cuenta que no podrás cambiar este valor a cualquier nombre de usuario o preferred_username que ya esté en uso para hacerse pasar por un usuario diferente.

Recuperar/Cambiar Contraseña

Es posible recuperar una contraseña solo conociendo el nombre de usuario (o email o teléfono son aceptados) y teniendo acceso a él, ya que se enviará un código allí:

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

La respuesta del servidor siempre será positiva, como si el nombre de usuario existiera. No puedes utilizar este método para enumerar usuarios.

Con el código puedes cambiar la contraseña con:

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

Para cambiar la contraseña, necesitas conocer la contraseña anterior:

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

Autenticación

Un grupo de usuarios admite diferentes formas de autenticación. Si tienes un nombre de usuario y contraseña, también hay diferentes métodos admitidos para iniciar sesión. Además, cuando un usuario se autentica en el grupo, se le otorgan 3 tipos de tokens: El Token de ID, el Token de Acceso y el Token de Actualización.

  • Token de ID: Contiene reclamaciones sobre la identidad del usuario autenticado, como nombre, correo electrónico y número de teléfono. El token de ID también se puede utilizar para autenticar usuarios en sus servidores de recursos o aplicaciones de servidor. Debes verificar la firma del token de ID antes de poder confiar en cualquier reclamación dentro del token de ID si lo usas en aplicaciones externas.

  • El Token de ID es el token que contiene los valores de los atributos del usuario, incluso los personalizados.

  • Token de Acceso: Contiene reclamaciones sobre el usuario autenticado, una lista de los grupos de usuarios del usuario y una lista de alcances. El propósito del token de acceso es autorizar operaciones de API en el contexto del usuario en el grupo de usuarios. Por ejemplo, puedes usar el token de acceso para conceder a tu usuario acceso para agregar, cambiar o eliminar atributos de usuario.

  • Token de Actualización: Con los tokens de actualización puedes obtener nuevos Tokens de ID y Tokens de Acceso para el usuario hasta que el token de actualización sea inválido. Por defecto, el token de actualización caduca 30 días después de que tu usuario de la aplicación inicie sesión en tu grupo de usuarios. Cuando creas una aplicación para tu grupo de usuarios, puedes establecer la expiración del token de actualización de la aplicación a cualquier valor entre 60 minutos y 10 años.

ADMIN_NO_SRP_AUTH & ADMIN_USER_PASSWORD_AUTH

Este es el flujo de autenticación del lado del servidor:

  • La aplicación del lado del servidor llama a la operación de API AdminInitiateAuth (en lugar de InitiateAuth). Esta operación requiere credenciales de AWS con permisos que incluyan cognito-idp:AdminInitiateAuth y cognito-idp:AdminRespondToAuthChallenge. La operación devuelve los parámetros de autenticación requeridos.

  • Después de que la aplicación del lado del servidor tenga los parámetros de autenticación, llama a la operación de API AdminRespondToAuthChallenge. La operación de API AdminRespondToAuthChallenge solo tiene éxito cuando proporcionas credenciales de AWS.

Este método NO está habilitado de forma predeterminada.

Para iniciar sesión necesitas saber:

  • ID del grupo de usuarios

  • ID del cliente

  • nombre de usuario

  • contraseña

  • secreto del cliente (solo si la aplicación está configurada para usar un secreto)

Para poder iniciar sesión con este método, la aplicación debe permitir iniciar sesión con ALLOW_ADMIN_USER_PASSWORD_AUTH. Además, para realizar esta acción necesitas credenciales con los permisos cognito-idp:AdminInitiateAuth y 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
Código para Iniciar sesión

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

### AUTENTICACIÓN\_DE\_USUARIO\_CONTRASEÑA

Este método es otro flujo de autenticación simple y **tradicional de usuario y contraseña**. Se recomienda **migrar un método de autenticación tradicional** a Cognito y luego **desactivarlo** y **utilizar** el método **ALLOW\_USER\_SRP\_AUTH** en su lugar (ya que este nunca envía la contraseña a través de la red).\
Este **método NO está habilitado** de forma predeterminada.

La principal **diferencia** con el **método de autenticación anterior** en el código es que **no necesitas conocer el ID del grupo de usuarios** y que **no necesitas permisos adicionales** en el grupo de usuarios de Cognito.

Para **iniciar sesión** necesitas saber:

- ID del cliente
- nombre de usuario
- contraseña
- secreto del cliente (solo si la aplicación está configurada para usar un secreto)

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

Para **poder iniciar sesión con este método**, la aplicación debe permitir iniciar sesión con 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

AUTENTICACIÓN CON REFRESH_TOKEN & REFRESH_TOKEN

Este método siempre va a ser válido (no se puede desactivar) pero necesitas tener un refresh token válido.

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

Última actualización