Cognito User Pools

Impara l'hacking di AWS da zero a eroe con htARTE (Esperto Red Team di HackTricks AWS)!

Altri modi per supportare HackTricks:

Informazioni di base

Un pool di utenti è una directory degli utenti in Amazon Cognito. Con un pool di utenti, i tuoi utenti possono effettuare l'accesso alla tua app web o mobile tramite Amazon Cognito, o federarsi attraverso un provider di identità di terze parti (IdP). Che i tuoi utenti accedano direttamente o tramite un terzo, tutti i membri del pool degli utenti hanno un profilo di directory a cui puoi accedere tramite un SDK.

I pool degli utenti forniscono:

  • Servizi di registrazione e accesso.

  • Un'interfaccia utente web integrata e personalizzabile per l'accesso degli utenti.

  • Accesso tramite social con Facebook, Google, Accesso con Amazon e Accedi con Apple, e tramite provider di identità SAML e OIDC dal tuo pool di utenti.

  • Gestione della directory degli utenti e profili utente.

  • Funzionalità di sicurezza come autenticazione multi-fattore (MFA), controlli per credenziali compromesse, protezione da takeover dell'account, e verifica tramite telefono ed email.

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

Il codice sorgente delle applicazioni conterrà di solito anche l'ID del pool degli utenti e l'ID dell'applicazione client, (e talvolta il segreto dell'applicazione?) che sono necessari per il login a un Pool degli Utenti di Cognito.

Potenziali attacchi

  • Registrazione: Per impostazione predefinita un utente può registrarsi da solo, quindi potrebbe creare un utente per sé stesso.

  • Enumerazione degli utenti: La funzionalità di registrazione può essere utilizzata per trovare nomi utente che esistono già. Questa informazione può essere utile per l'attacco di forza bruta.

  • Forza bruta per il login: Nella sezione Autenticazione hai tutti i metodi che un utente deve utilizzare per effettuare l'accesso, potresti provare a forzarli per trovare credenziali valide.

Strumenti per il pentesting

  • Pacu, il framework di sfruttamento AWS, include ora i moduli "cognito__enum" e "cognito__attack" che automatizzano l'enumerazione di tutti gli asset di Cognito in un account e segnalano configurazioni deboli, attributi utente utilizzati per il controllo degli accessi, ecc., e automatizzano anche la creazione degli utenti (incluso il supporto MFA) e l'escalation dei privilegi basata su attributi personalizzabili modificabili, credenziali del pool di identità utilizzabili, ruoli assumibili nei token di identità, ecc.

Per una descrizione delle funzioni dei moduli, consulta la parte 2 del post sul blog. Per le istruzioni di installazione, consulta la pagina principale di Pacu.

Utilizzo

Esempio di utilizzo di cognito__attack per tentare la creazione di utenti e tutti i vettori di escalation dei privilegi contro un pool di identità e un client del pool di utenti specifico:

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

Esempio di utilizzo di cognito__enum per raccogliere tutti i pool utenti, client pool utenti, pool identità, utenti, ecc. visibili nell'account AWS corrente:

Pacu (new:test) > run cognito__enum
  • Cognito Scanner è uno strumento CLI in python che implementa diversi attacchi su Cognito, inclusa la creazione indesiderata di account e l'account oracle.

Installazione

$ pip install cognito-scanner

Utilizzo

$ cognito-scanner --help

Per ulteriori informazioni controlla https://github.com/padok-team/cognito-scanner

Registrazione

I User Pools permettono per impostazione predefinita 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 ti indica che è necessario fornire ulteriori dettagli sull'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 gli attributi personalizzati iniziano con "custom:". Sappi anche che durante la registrazione non puoi creare nuovi attributi personalizzati per l'utente. Puoi solo assegnare un valore agli attributi predefiniti (anche se non sono richiesti) e agli attributi personalizzati specificati.

Oppure semplicemente per verificare se esiste un ID client. 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 gli utenti

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

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

Verifica della Registrazione

Cognito consente di verificare un nuovo utente verificando il suo indirizzo email o numero di telefono. Pertanto, quando si crea un utente, di solito sarà necessario almeno il nome utente e la password e l'indirizzo email e/o il numero di telefono. Basta impostarne uno che controlli in modo da ricevere il codice per verificare il tuo account utente appena 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 utilizzare lo stesso indirizzo email e numero di telefono, quando è necessario 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 del genere:

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 dell'attributo personalizzato

Potresti trovare attributi personalizzati in uso (come isAdmin), poiché per impostazione predefinita è possibile cambiare i valori dei propri attributi potresti essere in grado di aumentare i privilegi cambiando il valore da solo!

Privilegi di modifica dell'email/nome utente

Puoi usare 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 l'email o il 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'applicazione non controlla ciò potresti impersonare altri utenti.

Inoltre, nota che puoi inserire qualsiasi cosa nel campo name modificando semplicemente l'attributo del nome. Se un'applicazione sta controllando quel campo per qualche motivo anziché l'email (o qualsiasi altro attributo) potresti essere in grado di impersonare altri utenti.

In ogni caso, 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 ricevuto in 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 effettuare l'accesso con un nome utente preferito dall'utente. Nota che non sarà possibile cambiare questo valore in qualsiasi nome utente o preferred_username già in uso per impersonare un utente diverso.

Recupero/Cambio Password

È possibile recuperare una password conoscendo solo il nome utente (o l'email o il telefono sono accettati) e avendo accesso ad esso poiché verrà inviato un codice 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 l'username esistesse. Non è possibile 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 pool utenti supporta diversi metodi di autenticazione. Se si dispone di nome utente e password, sono supportati anche diversi metodi per effettuare il login. Inoltre, quando un utente è autenticato nel Pool vengono forniti 3 tipi di token: l'ID Token, l'Access token e il Refresh token.

  • ID Token: Contiene informazioni sull'identità dell'utente autenticato, come nome, email e numero di telefono. L'ID token può anche essere utilizzato per autenticare gli utenti ai server delle risorse o alle applicazioni server. È necessario verificare la firma dell'ID token prima di poter fidarsi di qualsiasi informazione all'interno dell'ID token se lo si utilizza in applicazioni esterne.

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

  • Access Token: Contiene informazioni sull'utente autenticato, un elenco dei gruppi dell'utente e un elenco di ambiti. Lo scopo dell'access token è autorizzare le operazioni API nel contesto dell'utente nel pool utenti. Ad esempio, è possibile utilizzare l'access token per concedere all'utente l'accesso per aggiungere, modificare o eliminare attributi dell'utente.

  • Refresh Token: Con i refresh token è possibile ottenere nuovi ID Token e Access Token per l'utente fino a quando il refresh token non è più valido. Per impostazione predefinita, il refresh token scade 30 giorni dopo che l'utente dell'applicazione accede al pool utenti. Quando si crea un'applicazione per il pool utenti, è possibile impostare la scadenza del refresh token dell'applicazione su qualsiasi valore compreso 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 (anziché InitiateAuth). Questa operazione richiede credenziali AWS con autorizzazioni 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 si forniscono le credenziali AWS.

Questo metodo NON è abilitato per impostazione predefinita.

Per effettuare il login è necessario conoscere:

  • ID del pool utenti

  • ID client

  • nome utente

  • password

  • segreto del client (solo se l'applicazione è 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 sono necessarie credenziali con le autorizzazioni 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

import boto3
import botocore
import hmac
import hashlib
import base64


client_id = "<client-id>"
user_pool_id = "<user-pool-id>"
client_secret = "<client-secret>"
username = "<username>"
password = "<pwd>"

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

AUTENTICAZIONE CON PASSWORD DELL'UTENTE

Questo metodo è un altro flusso di autenticazione semplice e tradizionale con utente e password. Si consiglia di migrare un metodo di autenticazione tradizionale a Cognito e successivamente disabilitarlo e utilizzare invece il metodo ALLOW_USER_SRP_AUTH (poiché non invia mai la password sulla rete). Questo metodo NON è abilitato per impostazione predefinita.

La principale differenza con il metodo di autenticazione precedente nel codice è che non è necessario conoscere l'ID del pool di utenti e non sono necessari permessi aggiuntivi nel pool di utenti di Cognito.

Per effettuare il login è necessario conoscere:

  • ID client

  • nome utente

  • password

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

Per poter effettuare il login con questo metodo, l'applicazione deve consentire il login con ALLOW_USER_PASSWORD_AUTH.

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

Codice Python per il Login

import boto3
import botocore
import hmac
import hashlib
import base64


client_id = "<client-id>"
user_pool_id = "<user-pool-id>"
client_secret = "<client-secret>"
username = "<username>"
password = "<pwd>"

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.initiate_auth(
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))

AUTENTICAZIONE_USER_SRP

Questo scenario è simile al precedente ma anziché inviare la password attraverso la rete per effettuare il login, viene eseguita un'autenticazione di sfida (quindi la password non naviga nemmeno criptata attraverso la rete). Questo metodo è abilitato per impostazione predefinita.

Per effettuare il login è necessario conoscere:

  • ID del pool utenti

  • ID del client

  • nome utente

  • password

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

Codice per il login

```python from warrant.aws_srp import AWSSRP import os

USERNAME='xxx' PASSWORD='yyy' POOL_ID='us-east-1_zzzzz' CLIENT_ID = '12xxxxxxxxxxxxxxxxxxxxxxx' CLIENT_SECRET = 'secreeeeet' os.environ["AWS_DEFAULT_REGION"] = ""

aws = AWSSRP(username=USERNAME, password=PASSWORD, pool_id=POOL_ID, client_id=CLIENT_ID, client_secret=CLIENT_SECRET) tokens = aws.authenticate_user() id_token = tokens['AuthenticationResult']['IdToken'] refresh_token = tokens['AuthenticationResult']['RefreshToken'] access_token = tokens['AuthenticationResult']['AccessToken'] token_type = tokens['AuthenticationResult']['TokenType']

</details>

### AUTENTICAZIONE CON REFRESH TOKEN E REFRESH TOKEN

Questo **metodo sarà sempre valido** (non può essere disabilitato) ma è necessario avere un refresh token valido.
```bash
aws cognito-idp initiate-auth \
--client-id 3ig6h5gjm56p1ljls1prq2miut \
--auth-flow REFRESH_TOKEN_AUTH \
--region us-east-1 \
--auth-parameters 'REFRESH_TOKEN=<token>'

Codice per aggiornare

import boto3
import botocore
import hmac
import hashlib
import base64

client_id = "<client-id>"
token = '<token>'

boto_client = boto3.client('cognito-idp', region_name='<region>')

def refresh(client_id, refresh_token):
try:
return boto_client.initiate_auth(
ClientId=client_id,
AuthFlow='REFRESH_TOKEN_AUTH',
AuthParameters={
'REFRESH_TOKEN': refresh_token
}
)
except botocore.exceptions.ClientError as e:
return e.response


print(refresh(client_id, token))

CUSTOM_AUTH

In questo caso, l'autenticazione verrà eseguita tramite l'esecuzione di una funzione lambda.

Sicurezza Extra

Sicurezza Avanzata

Di default è disabilitata, ma se abilitata, Cognito potrebbe essere in grado di individuare tentativi di takeover dell'account. Per ridurre al minimo la probabilità, dovresti effettuare il login da una rete nella stessa città, utilizzando lo stesso user agent (e IP se possibile).

MFA Ricorda dispositivo

Se l'utente effettua il login dallo stesso dispositivo, l'MFA potrebbe essere bypassato, quindi prova a effettuare il login dallo stesso browser con gli stessi metadati (IP?) per cercare di aggirare la protezione MFA.

Ruoli IAM dei Gruppi del Pool degli Utenti

È possibile aggiungere utenti ai gruppi del Pool degli Utenti che sono correlati a ruoli IAM. Inoltre, gli utenti possono essere assegnati a più di un gruppo con diversi ruoli IAM allegati.

Si noti che anche se un gruppo è all'interno di un gruppo con un ruolo IAM allegato, per poter accedere alle credenziali IAM di quel gruppo è necessario che il Pool degli Utenti sia fidato da un Pool di Identità (e conoscere i dettagli di quel Pool di Identità).

Un altro requisito per ottenere il ruolo IAM indicato nell'IdToken quando un utente viene autenticato nel Pool degli Utenti (aws cognito-idp initiate-auth...) è che il fornitore di autenticazione Identity Provider indichi che il ruolo deve essere selezionato dal token.

I ruoli a cui un utente ha accesso sono all'interno dell'IdToken, e un utente può selezionare quale ruolo desidera ottenere le credenziali con il --custom-role-arn da aws cognito-identity get-credentials-for-identity. Tuttavia, se l'opzione predefinita è quella configurata (usa ruolo predefinito), e si tenta di accedere a un ruolo dall'IdToken, si otterrà un errore (per questo è necessaria la configurazione precedente):

An error occurred (InvalidParameterException) when calling the GetCredentialsForIdentity operation: Only SAML providers and providers with RoleMappings support custom role ARN.

Si noti che il ruolo assegnato a un Gruppo di Pool Utenti deve essere accessibile dall'Identity Provider che affida la Pool Utenti (poiché le credenziali di sessione del ruolo IAM verranno ottenute da esso).

```json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "cognito-identity.amazonaws.com" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "cognito-identity.amazonaws.com:aud": "us-east-1:2361092e-9db6-a876-1027-10387c9de439" }, "ForAnyValue:StringLike": { "cognito-identity.amazonaws.com:amr": "authenticated" } } } ] }js ```Impara l'hacking su AWS da zero a eroe con htARTE (Esperto Red Team di HackTricks su AWS)!

Altri modi per supportare HackTricks:

Last updated