Cognito User Pools

Support HackTricks

Basic Information

Un user pool è un directory di utenti in Amazon Cognito. Con un user pool, i tuoi utenti possono accedere alla tua app web o mobile tramite Amazon Cognito, o federarsi tramite un fornitore di identità di terze parti (IdP). Che i tuoi utenti accedano direttamente o tramite una terza parte, tutti i membri del user pool hanno un profilo di directory a cui puoi accedere tramite un SDK.

I user pool forniscono:

  • Servizi di registrazione e accesso.

  • Un'interfaccia web personalizzabile integrata per accedere gli utenti.

  • Accesso sociale con Facebook, Google, Login con Amazon e Accesso con Apple, e tramite fornitori di identità SAML e OIDC dal tuo user pool.

  • Gestione della directory degli utenti e profili utente.

  • Funzionalità di sicurezza come l'autenticazione a più fattori (MFA), controlli per credenziali compromesse, protezione contro il takeover dell'account e verifica di telefono ed email.

  • Flussi di lavoro personalizzati e migrazione degli utenti tramite trigger AWS Lambda.

Il codice sorgente delle applicazioni conterrà solitamente anche il user pool ID e il client application ID, (e a volte il segreto dell'applicazione?) necessari per un utente per accedere a un Cognito User Pool.

Potential attacks

  • Registrazione: Per impostazione predefinita, un utente può registrarsi, quindi potrebbe creare un utente per se stesso.

  • Enumerazione utenti: La funzionalità di registrazione può essere utilizzata per trovare nomi utente che già esistono. Queste informazioni possono essere utili per l'attacco di forza bruta.

  • Login brute-force: Nella sezione Authentication hai tutti i metodi che un utente ha per accedere, potresti provare a forzare la loro ricerca di credenziali valide.

Tools for pentesting

  • Pacu, ora include i moduli cognito__enum e cognito__attack che automatizzano l'enumerazione di tutte le risorse Cognito in un account e segnalano configurazioni deboli, attributi utente utilizzati per il controllo degli accessi, ecc., e automatizzano anche la creazione di utenti (incluso il supporto MFA) e l'escalation dei privilegi basata su attributi personalizzati modificabili, credenziali di pool di identità utilizzabili, ruoli assunibili nei token id, ecc. Per una descrizione delle funzioni dei moduli, vedere la parte 2 del blog post. Per le istruzioni di installazione, vedere la pagina principale di Pacu.

# Run cognito__enum usage to gather all user pools, user pool clients, identity pools, users, etc. visible in the current AWS account
Pacu (new:test) > run cognito__enum

# cognito__attack usage to attempt user creation and all privesc vectors against a given identity pool and user pool client:
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
  • Cognito Scanner è uno strumento CLI in python che implementa diversi attacchi su Cognito, inclusa la creazione non desiderata di account e l'oracolo degli account. Controlla questo link per ulteriori informazioni.

# Install
pip install cognito-scanner
# Run
cognito-scanner --help
python cognito-attribute-enu.py -client_id 16f1g98bfuj9i0g3f8be36kkrl

Registrazione

User Pools consente per default di registrare nuovi utenti.

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

Se chiunque può registrarsi

Potresti trovare un errore che indica che devi fornire più dettagli riguardo all'utente:

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

Puoi fornire i dettagli necessari con un JSON come:

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

Puoi utilizzare questa funzionalità anche per enumerare gli utenti esistenti. Questo è il messaggio di errore quando un utente esiste già con quel nome:

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

Nota nel comando precedente come i custom attributes iniziano con "custom:". Sappi anche che durante la registrazione non puoi creare nuovi custom attributes per l'utente. Puoi solo dare valore ai default attributes (anche se non sono richiesti) e ai custom attributes specificati.

O semplicemente per testare se un client id esiste. Questo è l'errore se il client-id non esiste:

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

Se solo l'amministratore può registrare utenti

Troverai questo errore e non sarai in grado di registrare o enumerare utenti:

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

Verifying Registration

Cognito consente di verificare un nuovo utente verificando la sua email o il numero di telefono. Pertanto, quando si crea un utente, di solito sarà richiesto almeno il nome utente e la password e l'email e/o il numero di telefono. Basta impostare uno che controlli in modo da ricevere il codice per verificare il tuo nuovo account utente creato in questo modo:

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

Anche se sembra che tu possa usare la stessa email e numero di telefono, quando devi verificare l'utente creato Cognito si lamenterà dell'uso delle stesse informazioni e non ti permetterà di verificare l'account.

Escalation dei privilegi / Aggiornamento degli attributi

Per impostazione predefinita, un utente può modificare il valore dei suoi attributi con qualcosa come:

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

Privilegi di escalation degli attributi personalizzati

Potresti trovare attributi personalizzati utilizzati (come isAdmin), poiché per impostazione predefinita puoi cambiare i valori dei tuoi attributi potresti essere in grado di escalare i privilegi cambiando il valore tu stesso!

Privilegi di escalation nella modifica di email/nome utente

Puoi utilizzare questo per modificare l'email e il numero di telefono di un utente, ma poi, anche se l'account rimane verificato, quegli attributi sono impostati in stato non verificato (devi verificarli di nuovo).

Non sarai in grado di accedere con email o numero di telefono fino a quando non li verifichi, ma sarai in grado di accedere con il nome utente. Nota che anche se l'email è stata modificata e non verificata apparirà nel Token ID all'interno del campo email e il campo email_verified sarà falso, ma se l'app non sta controllando questo potresti impersonare altri utenti.

Inoltre, nota che puoi mettere qualsiasi cosa all'interno del campo name semplicemente modificando l'attributo name. Se un'app controlla quel campo per qualche motivo invece di email (o qualsiasi altro attributo) potresti essere in grado di impersonare altri utenti.

Comunque, se per qualche motivo hai cambiato la tua email, ad esempio con una nuova a cui puoi accedere, puoi confermare l'email con il codice che hai ricevuto a quell'indirizzo email:

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

Usa phone_number invece di email per cambiare/verificare un nuovo numero di telefono.

L'amministratore potrebbe anche abilitare l'opzione per accedere con un nome utente preferito dall'utente. Tieni presente che non potrai cambiare questo valore in nessun nome utente o preferred_username già in uso per impersonare un altro utente.

Recupera/Cambia Password

È possibile recuperare una password semplicemente conoscendo il nome utente (o email o telefono sono accettati) e avendo accesso ad esso poiché un codice verrà inviato lì:

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

La risposta del server sarà sempre positiva, come se il nome utente esistesse. Non puoi utilizzare questo metodo per enumerare gli utenti.

Con il codice puoi cambiare la password con:

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

Per cambiare la password è necessario conoscere la password precedente:

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

Autenticazione

Un user pool supporta diversi modi per autenticarsi. Se hai un nome utente e una password, ci sono anche diversi metodi supportati per effettuare il login. Inoltre, quando un utente è autenticato nel Pool, vengono forniti 3 tipi di token: il Token ID, il Token di Accesso e il Token di Refresh.

  • Token ID: Contiene affermazioni riguardo all'identità dell'utente autenticato, come name, email e phone_number. Il token ID può anche essere utilizzato per autenticare gli utenti ai tuoi server di risorse o applicazioni server. Devi verificare la firma del token ID prima di poter fidarti di qualsiasi affermazione all'interno del token ID se lo usi in applicazioni esterne.

  • Il Token ID è il token che contiene i valori degli attributi dell'utente, anche quelli personalizzati.

  • Token di Accesso: Contiene affermazioni riguardo all'utente autenticato, un elenco dei gruppi dell'utente e un elenco di scope. Lo scopo del token di accesso è di autorizzare le operazioni API nel contesto dell'utente nel user pool. Ad esempio, puoi utilizzare il token di accesso per concedere al tuo utente l'accesso per aggiungere, modificare o eliminare attributi utente.

  • Token di Refresh: Con i token di refresh puoi ottenere nuovi Token ID e Token di Accesso per l'utente fino a quando il token di refresh non è invalido. Per default, il token di refresh scade 30 giorni dopo che l'utente della tua applicazione accede al tuo user pool. Quando crei un'applicazione per il tuo user pool, puoi impostare la scadenza del token di refresh dell'applicazione a qualunque valore tra 60 minuti e 10 anni.

ADMIN_NO_SRP_AUTH & ADMIN_USER_PASSWORD_AUTH

Questo è il flusso di autenticazione lato server:

  • L'applicazione lato server chiama l'operazione API AdminInitiateAuth (invece di InitiateAuth). Questa operazione richiede credenziali AWS con permessi che includono cognito-idp:AdminInitiateAuth e cognito-idp:AdminRespondToAuthChallenge. L'operazione restituisce i parametri di autenticazione richiesti.

  • Dopo che l'applicazione lato server ha i parametri di autenticazione, chiama l'operazione API AdminRespondToAuthChallenge. L'operazione API AdminRespondToAuthChallenge ha successo solo quando fornisci credenziali AWS.

Questo metodo NON è abilitato per impostazione predefinita.

Per effettuare il login devi conoscere:

  • id del user pool

  • id del client

  • nome utente

  • password

  • segreto del client (solo se l'app è configurata per utilizzare un segreto)

Per poter effettuare il login con questo metodo, l'applicazione deve consentire il login con ALLOW_ADMIN_USER_PASSWORD_AUTH. Inoltre, per eseguire questa azione hai bisogno di credenziali con i permessi cognito-idp:AdminInitiateAuth e 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
Codice per il Login

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

Questo metodo è un altro semplice e **tradizionale flusso di autenticazione utente e password**. È consigliato **migrere un metodo di autenticazione tradizionale** **a Cognito** e **consigliato** poi **disabilitarlo** e **utilizzare** invece il metodo **ALLOW\_USER\_SRP\_AUTH** (poiché quest'ultimo non invia mai la password attraverso la rete).\
Questo **metodo NON è abilitato** per impostazione predefinita.

La principale **differenza** con il **metodo di autenticazione precedente** all'interno del codice è che **non è necessario conoscere l'ID del pool utenti** e che **non sono necessarie autorizzazioni extra** nel Cognito User Pool.

Per **accedere** è **necessario** conoscere:

* client id
* username
* password
* client secret (solo se l'app è configurata per utilizzare un segreto)

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

Per **poter accedere con questo metodo**, quell'applicazione deve consentire l'accesso 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

REFRESH_TOKEN_AUTH & REFRESH_TOKEN

Questo metodo sarà sempre valido (non può essere disabilitato) ma è necessario avere un token di aggiornamento valido.

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

Last updated