# Cognito User Pools

{{#include ../../../../banners/hacktricks-training.md}}

## Basiese Inligting

'n Gebruikerspoel is 'n gebruikersgids in Amazon Cognito. Met 'n gebruikerspoel kan jou gebruikers **aanmeld by jou web- of mobiele toepassing** deur Amazon Cognito, **of federate** deur 'n **derdeparty** identiteitsverskaffer (IdP). Of jou gebruikers nou direk of deur 'n derdeparty aanmeld, het alle lede van die gebruikerspoel 'n gidsprofiel wat jy deur 'n SDK kan toegang.

Gebruikerspoele bied:

- Teken-in en teken-aan dienste.
- 'n Ingeboude, aanpasbare web UI om gebruikers aan te meld.
- Sosiale aanmelding met Facebook, Google, Login with Amazon, en Sign in with Apple, en deur SAML en OIDC identiteitsverskaffers van jou gebruikerspoel.
- Gebruikersgidsbestuur en gebruikersprofiele.
- Sekuriteitskenmerke soos multi-faktor verifikasie (MFA), kontrole vir gecompromitteerde geloofsbriewe, rekening oorname beskerming, en telefoon- en e-posverifikasie.
- Aangepaste werksvloeie en gebruikersmigrasie deur AWS Lambda triggers.

**Bronkode** van toepassings sal gewoonlik ook die **gebruikerspoel ID** en die **klienttoepassing ID** bevat, (en soms die **toepassing geheim**?) wat nodig is vir 'n **gebruiker om aan te meld** by 'n Cognito Gebruikerspoel.

### Potensiële aanvalle

- **Registrasie**: Standaard kan 'n gebruiker homself registreer, so hy kan 'n gebruiker vir homself skep.
- **Gebruikersenumerasie**: Die registrasiefunksionaliteit kan gebruik word om gebruikersname te vind wat reeds bestaan. Hierdie inligting kan nuttig wees vir die brute-force aanval.
- **Aanmeld brute-force**: In die [**Verifikasie**](cognito-user-pools.md#authentication) afdeling het jy al die **metodes** wat 'n gebruiker het om te **aanmeld**, jy kan probeer om hulle te brute-force **geldige geloofsbriewe te vind**.

### Gereedskap vir pentesting

- [Pacu](https://github.com/RhinoSecurityLabs/pacu), sluit nou die `cognito__enum` en `cognito__attack` modules in wat die enumerasie van alle Cognito bates in 'n rekening outomatiseer en swak konfigurasies, gebruikersattribuut wat vir toegangbeheer gebruik word, ens., merk, en outomatiseer ook gebruikersskepping (insluitend MFA-ondersteuning) en voorregverhoging gebaseer op aanpasbare aangepaste attribuut, bruikbare identiteitspoel geloofsbriewe, aanneembare rolle in id tokens, ens.\
Vir 'n beskrywing van die modules se funksies, sien deel 2 van die [blogpos](https://rhinosecuritylabs.com/aws/attacking-aws-cognito-with-pacu-p2). Vir installasie-instruksies, sien die hoof [Pacu](https://github.com/RhinoSecurityLabs/pacu) bladsy.
```bash
# 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](https://github.com/padok-team/cognito-scanner) is 'n CLI-gereedskap in python wat verskillende aanvalle op Cognito implementeer, insluitend ongewenste rekening skep en rekening oracle. Kyk na [this link](https://github.com/padok-team/cognito-scanner) vir meer inligting.
```bash
# Install
pip install cognito-scanner
# Run
cognito-scanner --help
```
- [CognitoAttributeEnum](https://github.com/punishell/CognitoAttributeEnum): Hierdie skrip maak dit moontlik om geldige eienskappe vir gebruikers te enumereer.
```bash
python cognito-attribute-enu.py -client_id 16f1g98bfuj9i0g3f8be36kkrl
```
## Registrasie

User Pools laat **per standaard** toe om **nuwe gebruikers te registreer**.
```bash
aws cognito-idp sign-up --client-id <client-id> \
--username <username> --password <password> \
--region <region> --no-sign-request
```
#### As iemand kan registreer

Jy mag 'n fout vind wat aandui dat jy **meer besonderhede** oor die gebruiker moet verskaf:
```
An error occurred (InvalidParameterException) when calling the SignUp operation: Attributes did not conform to the schema: address: The attribute is required
```
U kan die nodige besonderhede verskaf met 'n JSON soos:
```json
--user-attributes '[{"Name": "email", "Value": "carlospolop@gmail.com"}, {"Name":"gender", "Value": "M"}, {"Name": "address", "Value": "street"}, {"Name": "custom:custom_name", "Value":"supername&\"*$"}]'
```
U kan hierdie funksionaliteit ook gebruik om **bestaande gebruikers te enumereer.** Dit is die foutboodskap wanneer 'n gebruiker reeds met daardie naam bestaan:
```
An error occurred (UsernameExistsException) when calling the SignUp operation: User already exists
```
> [!NOTE]
> Let op in die vorige opdrag hoe die **aangepaste eienskappe begin met "custom:"**.\
> Weet ook dat wanneer jy registreer jy **nie nuwe aangepaste eienskappe vir die gebruiker kan skep nie**. Jy kan slegs waarde gee aan **standaard eienskappe** (selfs al is hulle nie vereis nie) en **aangepaste eienskappe wat gespesifiseer is**.

Of net om te toets of 'n kliënt-id bestaan. Dit is die fout as die kliënt-id nie bestaan nie:
```
An error occurred (ResourceNotFoundException) when calling the SignUp operation: User pool client 3ig612gjm56p1ljls1prq2miut does not exist.
```
#### As slegs admin gebruikers kan registreer

Jy sal hierdie fout vind en jy sal nie in staat wees om gebruikers te registreer of te enumereer nie:
```
An error occurred (NotAuthorizedException) when calling the SignUp operation: SignUp is not permitted for this user pool
```
### Verifying Registration

Cognito laat toe om **'n nuwe gebruiker te verifieer deur sy e-pos of telefoonnommer te verifieer**. Daarom, wanneer jy 'n gebruiker skep, sal jy gewoonlik ten minste die gebruikersnaam en wagwoord en die **e-pos en/of telefoonnommer** benodig. Stel net een **wat jy beheer** sodat jy die kode sal ontvang om **jou** nuut geskepte gebruiker **rekening** te verifieer soos volg:
```bash
aws cognito-idp confirm-sign-up --client-id <cliet_id> \
--username aasdasd2 --confirmation-code <conf_code> \
--no-sign-request --region us-east-1
```
> [!WARNING]
> Selfs al **lyk dit of jy dieselfde e-pos** en telefoonnommer kan gebruik, wanneer jy die geskepte gebruiker moet verifieer, sal Cognito kla oor die gebruik van dieselfde inligting en **sal nie toelaat dat jy die rekening verifieer nie**.

### Privilege Escalation / Updating Attributes

Deur die standaard kan 'n gebruiker **die waarde van sy eienskappe verander** met iets soos:
```bash
aws cognito-idp update-user-attributes \
--region us-east-1 --no-sign-request \
--user-attributes Name=address,Value=street \
--access-token <access token>
```
#### Aangepaste attribuut privesc

> [!CAUTION]
> Jy mag **aangepaste attribuite** vind wat gebruik word (soos `isAdmin`), aangesien jy standaard **die waardes van jou eie attribuite kan verander** kan jy dalk **privileges eskaleer** deur die waarde self te verander!

#### E-pos/gebruikersnaam wysigings privesc

Jy kan dit gebruik om die **e-pos en telefoonnommer** van 'n gebruiker te **wysig**, maar dan, selfs al bly die rekening as geverifieer, is daardie attribuite **in 'n ongeverifieerde status gestel** (jy moet hulle weer verifieer).

> [!WARNING]
> Jy **sal nie in staat wees om in te log met e-pos of telefoonnommer** totdat jy hulle verifieer nie, maar jy sal **in staat wees om in te log met die gebruikersnaam**.\
> Let daarop dat selfs al is die e-pos gewysig en nie geverifieer nie, dit sal verskyn in die ID Token binne die **`email`** **veld** en die veld **`email_verified`** sal **vals** wees, maar as die app **nie kyk nie, kan jy ander gebruikers naboots**.

> Boonop, let daarop dat jy enigiets in die **`name`** veld kan plaas deur net die **naam attribuut** te wysig. As 'n app **kyk** na daardie veld om een of ander rede **in plaas van die `email`** (of enige ander attribuut) kan jy dalk **ander gebruikers naboots**.

In elk geval, as jy om een of ander rede jou e-pos verander het na 'n nuwe een wat jy kan toegang, kan jy die e-pos **bevestig met die kode wat jy in daardie e-posadres ontvang het**:
```bash
aws cognito-idp verify-user-attribute \
--access-token <access_token> \
--attribute-name email --code <code> \
--region <region> --no-sign-request
```
Gebruik **`phone_number`** in plaas van **`email`** om 'n **nuwe telefoonnommer** te verander/te verifieer.

> [!NOTE]
> Die admin kan ook die opsie aktief maak om **in te log met 'n gebruiker se verkose gebruikersnaam**. Let daarop dat jy nie hierdie waarde kan verander na **enige gebruikersnaam of verkose_gebruikersnaam wat reeds gebruik word** om 'n ander gebruiker na te boots nie.

### Herstel/Verander Wagwoord

Dit is moontlik om 'n wagwoord te herstel net deur **die gebruikersnaam** te ken (of e-pos of telefoon word aanvaar) en toegang daartoe te hê, aangesien 'n kode daar gestuur sal word:
```bash
aws cognito-idp forgot-password \
--client-id <client_id> \
--username <username/email/phone> --region <region>
```
> [!NOTE]
> Die antwoord van die bediener gaan altyd positief wees, soos as die gebruikersnaam bestaan. Jy kan nie hierdie metode gebruik om gebruikers te enumereer nie.

Met die kode kan jy die wagwoord verander met:
```bash
aws cognito-idp confirm-forgot-password \
--client-id <client_id> \
--username <username> \
--confirmation-code <conf_code> \
--password <pwd> --region <region>
```
Om die wagwoord te verander, moet jy **die vorige wagwoord weet**:
```bash
aws cognito-idp change-password \
--previous-password <value> \
--proposed-password <value> \
--access-token <value>
```
## Verifikasie

'n Gebruikerspoel ondersteun **verskillende maniere om te verifieer**. As jy 'n **gebruikersnaam en wagwoord** het, is daar ook **verskillende metodes** wat ondersteun word om aan te meld.\
Boonop, wanneer 'n gebruiker in die Poel **3 tipes tokens gegee word**: Die **ID Token**, die **Toegangstoken** en die **Herlaa token**.

- [**ID Token**](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-the-id-token.html): Dit bevat aansprake oor die **identiteit van die geverifieerde gebruiker**, soos `naam`, `e-pos`, en `telefoon_nommer`. Die ID-token kan ook gebruik word om **gebruikers te verifieer op jou hulpbronne of bedienertoepassings**. Jy moet die **handtekening** van die ID-token **verifieer** voordat jy enige aansprake binne die ID-token kan vertrou as jy dit in eksterne toepassings gebruik.
- Die ID Token is die token wat **die attribuutwaardes van die gebruiker bevat**, selfs die pasgemaakte.
- [**Toegangstoken**](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-the-access-token.html): Dit bevat aansprake oor die geverifieerde gebruiker, 'n lys van die **gebruiker se groepe, en 'n lys van skope**. Die doel van die toegangstoken is om **API-operasies te autoriseer** in die konteks van die gebruiker in die gebruikerspoel. Byvoorbeeld, jy kan die toegangstoken gebruik om **jou gebruiker toegang te gee** om gebruikersattribuut te voeg, te verander of te verwyder.
- [**Herlaa token**](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-the-refresh-token.html): Met herlaa tokens kan jy **nuwe ID Tokens en Toegangstokens** vir die gebruiker kry totdat die **herlaa token ongeldig is**. Deur **standaard** verval die herlaa token **30 dae nadat** jou toepassingsgebruiker in jou gebruikerspoel aanmeld. Wanneer jy 'n toepassing vir jou gebruikerspoel skep, kan jy die vervaldatum van die toepassingsherlaa token op **enige waarde tussen 60 minute en 10 jaar** stel.

### ADMIN_NO_SRP_AUTH & ADMIN_USER_PASSWORD_AUTH

Dit is die bediener-kant verifikasie vloei:

- Die bediener-kant toepassing roep die **`AdminInitiateAuth` API-operasie** aan (in plaas van `InitiateAuth`). Hierdie operasie vereis AWS-akkrediteer met toestemmings wat **`cognito-idp:AdminInitiateAuth`** en **`cognito-idp:AdminRespondToAuthChallenge`** insluit. Die operasie gee die vereiste verifikasieparameters terug.
- Nadat die bediener-kant toepassing die **verifikasieparameters** het, roep dit die **`AdminRespondToAuthChallenge` API-operasie** aan. Die `AdminRespondToAuthChallenge` API-operasie slaag slegs wanneer jy AWS-akkrediteer verskaf.

Hierdie **metode is NIE geaktiveer nie** deur standaard.

Om te **meld aan** moet jy **weet**:

- gebruikerspoel id
- kliënt id
- gebruikersnaam
- wagwoord
- kliënt geheim (slegs as die toepassing geconfigureer is om 'n geheim te gebruik)

> [!NOTE]
> Ten einde **met hierdie metode aan te meld**, moet daardie toepassing toelaat om aan te meld met `ALLOW_ADMIN_USER_PASSWORD_AUTH`.\
> Boonop, om hierdie aksie uit te voer, het jy akkrediteer met die toestemmings **`cognito-idp:AdminInitiateAuth`** en **`cognito-idp:AdminRespondToAuthChallenge`**
```python
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
```
<details>

<summary>Kode om in te log</summary>
```python
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))
```
</details>

### USER_PASSWORD_AUTH

Hierdie metode is 'n ander eenvoudige en **tradisionele gebruiker & wagwoord verifikasie** vloei. Dit word aanbeveel om 'n **tradisionele** verifikasie metode **na Cognito** te **migreer** en dan **aan te beveel** om dit te **deaktiveer** en dan die **ALLOW_USER_SRP_AUTH** metode te **gebruik** (aangesien dit nooit die wagwoord oor die netwerk stuur).\
Hierdie **metode is NIE geaktiveer** nie as standaard.

Die hoof **verskil** met die **vorige verifikasie metode** binne die kode is dat jy **nie die gebruiker poel ID** hoef te weet nie en dat jy **nie ekstra toestemmings** in die Cognito Gebruiker Poel nodig het nie.

Om te **log in** moet jy **weet**:

- kliënt id
- gebruikersnaam
- wagwoord
- kliënt geheim (slegs as die toepassing geconfigureer is om 'n geheim te gebruik)

> [!NOTE]
> Om **in staat te wees om met hierdie metode in te log** moet daardie toepassing toelaat om in te log met ALLOW_USER_PASSWORD_AUTH.
```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
```
<details>

<summary>Python kode om aan te meld</summary>
```python
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))
```
</details>

### USER_SRP_AUTH

Hierdie scenario is soortgelyk aan die vorige een, maar **in plaas daarvan om die wagwoord** deur die netwerk te stuur om in te log, word 'n **uitdaging-authentisering uitgevoer** (so geen wagwoord wat selfs versleuteld deur die netwerk beweeg nie).\
Hierdie **metode is standaard geaktiveer**.

Om te **log in** moet jy weet:

- gebruikerspoel id
- kliënt id
- gebruikersnaam
- wagwoord
- kliënt geheim (slegs as die app gekonfigureer is om 'n geheim te gebruik)

<details>

<summary>Code om in te log</summary>
```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"] = "<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>

### REFRESH_TOKEN_AUTH & REFRESH_TOKEN

Hierdie **metode gaan altyd geldig wees** (dit kan nie gedeaktiveer word nie) maar jy moet 'n geldige hernu token hê.
```bash
aws cognito-idp initiate-auth \
--client-id 3ig6h5gjm56p1ljls1prq2miut \
--auth-flow REFRESH_TOKEN_AUTH \
--region us-east-1 \
--auth-parameters 'REFRESH_TOKEN=<token>'
```
<details>

<summary>Kode om te verfris</summary>
```python
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))
```
</details>

### CUSTOM_AUTH

In hierdie geval gaan die **verifikasie** deur die **uitvoering van 'n lambda-funksie** plaasvind.

## Ekstra Sekuriteit

### Gevorderde Sekuriteit

Standaard is dit gedeaktiveer, maar as dit geaktiveer is, kan Cognito in staat wees om **rekening oorname** te vind. Om die waarskynlikheid te minimaliseer, moet jy aanmeld vanaf 'n **netwerk binne dieselfde stad, met dieselfde gebruikersagent** (en IP as dit moontlik is)**.**

### **MFA Onthou toestel**

As die gebruiker vanaf dieselfde toestel aanmeld, kan die MFA omseil word, probeer dus om vanaf dieselfde blaaiers met dieselfde metadata (IP?) aan te meld om die MFA-beskerming te probeer omseil.

## Gebruiker Pool Groepe IAM Rolle

Dit is moontlik om **gebruikers aan Gebruiker Pool** groepe toe te voeg wat verband hou met een **IAM rol**.\
Boonop kan **gebruikers** aan **meer as 1 groep met verskillende IAM rolle** toegeken word.

Let daarop dat selfs al is 'n groep binne 'n groep met 'n IAM rol aangeheg, dit nodig is dat die **Gebruiker Pool vertrou word deur 'n Identiteits Pool** (en die besonderhede van daardie Identiteits Pool ken).

Nog 'n vereiste om die **IAM rol aangedui in die IdToken** te verkry wanneer 'n gebruiker in die Gebruiker Pool geverifieer word (`aws cognito-idp initiate-auth...`), is dat die **Identiteits Verskaffer Verifikasie verskaffer** moet aandui dat die **rol uit die token gekies moet word.**

<figure><img src="../../../../images/image (250).png" alt=""><figcaption></figcaption></figure>

Die **rolle** waartoe 'n gebruiker toegang het, is **binne die `IdToken`**, en 'n gebruiker kan **kies watter rol hy graag krediete vir wil hê** met die **`--custom-role-arn`** van `aws cognito-identity get-credentials-for-identity`.\
As die **standaard opsie** egter die een is wat **gekonfigureer** is (`use default role`), en jy probeer om toegang tot 'n rol vanaf die IdToken te verkry, sal jy **fout** kry (dit is waarom die vorige konfigurasie nodig is):
```
An error occurred (InvalidParameterException) when calling the GetCredentialsForIdentity operation: Only SAML providers and providers with RoleMappings support custom role ARN.
```
> [!WARNING]
> Let daarop dat die rol wat aan 'n **User Pool Group** toegeken is, **toeganklik moet wees deur die Identiteitsverskaffer** wat **die User Pool vertrou** (aangesien die IAM-rol **sessie geloofsbriewe daaruit verkry gaan word**).
```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
```
{{#include ../../../../banners/hacktricks-training.md}}
