# Cognito User Pools

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

## Osnovne informacije

User pool je direktorijum korisnika u Amazon Cognito. Sa user pool-om, vaši korisnici mogu **da se prijave na vašu web ili mobilnu aplikaciju** putem Amazon Cognito, **ili da se federišu** putem **treće strane** provajdera identiteta (IdP). Bilo da se vaši korisnici prijavljuju direktno ili putem treće strane, svi članovi user pool-a imaju profil u direktorijumu kojem možete pristupiti putem SDK-a.

User pool-ovi pružaju:

- Usluge registracije i prijave.
- Ugrađeni, prilagodljivi web UI za prijavu korisnika.
- Društvenu prijavu putem Facebook-a, Google-a, Login with Amazon, i Sign in with Apple, kao i putem SAML i OIDC provajdera identiteta iz vašeg user pool-a.
- Upravljanje direktorijumom korisnika i korisničkim profilima.
- Bezbednosne funkcije kao što su višefaktorska autentifikacija (MFA), provere za kompromitovane akreditive, zaštita od preuzimanja naloga, i verifikacija telefona i email-a.
- Prilagođeni radni tokovi i migracija korisnika putem AWS Lambda okidača.

**Izvorni kod** aplikacija obično takođe sadrži **user pool ID** i **ID klijentske aplikacije**, (i ponekad **tajnu aplikacije**?) koji su potrebni za **prijavu korisnika** u Cognito User Pool.

### Potencijalni napadi

- **Registracija**: Po defaultu, korisnik se može registrovati sam, tako da može kreirati korisnika za sebe.
- **Enumeracija korisnika**: Funkcionalnost registracije može se koristiti za pronalaženje korisničkih imena koja već postoje. Ove informacije mogu biti korisne za napad brute-force.
- **Brute-force prijava**: U [**Autentifikaciji**](cognito-user-pools.md#authentication) imate sve **metode** koje korisnik može koristiti za **prijavu**, možete pokušati da ih brute-force-ujete **da pronađete validne akreditive**.

### Alati za pentesting

- [Pacu](https://github.com/RhinoSecurityLabs/pacu), sada uključuje `cognito__enum` i `cognito__attack` module koji automatizuju enumeraciju svih Cognito resursa u nalogu i označavaju slabe konfiguracije, atribute korisnika korišćene za kontrolu pristupa, itd., i takođe automatizuju kreiranje korisnika (uključujući podršku za MFA) i eskalaciju privilegija na osnovu modifikabilnih prilagođenih atributa, upotrebljivih akreditiva identiteta, preuzimljivih uloga u id tokenima, itd.\
Za opis funkcija modula pogledajte deo 2 [blog posta](https://rhinosecuritylabs.com/aws/attacking-aws-cognito-with-pacu-p2). Za uputstva za instalaciju pogledajte glavnu [Pacu](https://github.com/RhinoSecurityLabs/pacu) stranicu.
```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) je CLI alat u pythonu koji implementira različite napade na Cognito, uključujući neželjeno kreiranje naloga i oracle naloga. Proverite [this link](https://github.com/padok-team/cognito-scanner) za više informacija.
```bash
# Install
pip install cognito-scanner
# Run
cognito-scanner --help
```
- [CognitoAttributeEnum](https://github.com/punishell/CognitoAttributeEnum): Ovaj skript omogućava enumeraciju validnih atributa za korisnike.
```bash
python cognito-attribute-enu.py -client_id 16f1g98bfuj9i0g3f8be36kkrl
```
## Registracija

User Pools omogućava **podrazumevano** da se **registruju novi korisnici**.
```bash
aws cognito-idp sign-up --client-id <client-id> \
--username <username> --password <password> \
--region <region> --no-sign-request
```
#### Ako bilo ko može da se registruje

Možda ćete naići na grešku koja ukazuje da treba da **obezbedite više detalja** o korisniku:
```
An error occurred (InvalidParameterException) when calling the SignUp operation: Attributes did not conform to the schema: address: The attribute is required
```
Možete pružiti potrebne detalje sa JSON-om kao što je:
```json
--user-attributes '[{"Name": "email", "Value": "carlospolop@gmail.com"}, {"Name":"gender", "Value": "M"}, {"Name": "address", "Value": "street"}, {"Name": "custom:custom_name", "Value":"supername&\"*$"}]'
```
Možete koristiti ovu funkcionalnost takođe da **enumerišete postojeće korisnike.** Ovo je poruka o grešci kada korisnik već postoji sa tim imenom:
```
An error occurred (UsernameExistsException) when calling the SignUp operation: User already exists
```
> [!NOTE]
> Obratite pažnju na prethodnu komandu kako **prilagođene atribute počinju sa "custom:"**.\
> Takođe, znajte da prilikom registracije **ne možete kreirati nove prilagođene atribute za korisnika**. Možete samo dodeliti vrednost **podrazumevanim atributima** (čak i ako nisu obavezni) i **prilagođenim atributima koji su navedeni**.

Ili samo da testirate da li klijent ID postoji. Ovo je greška ako klijent-ID ne postoji:
```
An error occurred (ResourceNotFoundException) when calling the SignUp operation: User pool client 3ig612gjm56p1ljls1prq2miut does not exist.
```
#### Ako samo administrator može da registruje korisnike

Naći ćete ovu grešku i nećete moći da registrujete ili enumerišete korisnike:
```
An error occurred (NotAuthorizedException) when calling the SignUp operation: SignUp is not permitted for this user pool
```
### Verifikacija Registracije

Cognito omogućava da **verifikujete novog korisnika verifikovanjem njegovog emaila ili broja telefona**. Stoga, prilikom kreiranja korisnika obično će vam biti potrebni barem korisničko ime i lozinka, kao i **email i/ili broj telefona**. Samo postavite jedan **koji kontrolišete** kako biste primili kod za **verifikaciju vašeg** novokreiranog korisničkog **naloga** na sledeći način:
```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]
> Čak i ako **izgleda da možete koristiti istu email adresu** i broj telefona, kada treba da verifikujete kreiranog korisnika, Cognito će se žaliti na korišćenje istih informacija i **neće vam dozvoliti da verifikujete nalog**.

### Eskalacija privilegija / Ažuriranje atributa

Po defaultu, korisnik može **modifikovati vrednost svojih atributa** sa nečim poput:
```bash
aws cognito-idp update-user-attributes \
--region us-east-1 --no-sign-request \
--user-attributes Name=address,Value=street \
--access-token <access token>
```
#### Privesc prilagođenih atributa

> [!CAUTION]
> Možete pronaći **prilagođene atribute** koji se koriste (kao što je `isAdmin`), jer po defaultu možete **promeniti vrednosti svojih atributa**, možda ćete moći da **escalate privilegije** menjajući vrednost sami!

#### Privesc modifikacije emaila/korisničkog imena

Možete koristiti ovo da **modifikujete email i broj telefona** korisnika, ali tada, čak i ako račun ostane kao verifikovan, ti atributi su **postavljeni u status neproveren** (morate ih ponovo verifikovati).

> [!WARNING]
> Nećete moći da se prijavite sa emailom ili brojem telefona dok ih ne verifikujete, ali ćete moći da se prijavite sa korisničkim imenom.\
> Imajte na umu da čak i ako je email modifikovan i nije verifikovan, pojaviće se u ID Tokenu unutar **`email`** **polja** i polje **`email_verified`** će biti **false**, ali ako aplikacija **ne proverava to, možda ćete moći da se pretvarate da ste drugi korisnici**.

> Pored toga, imajte na umu da možete staviti bilo šta unutar **`name`** polja jednostavno modifikujući **atribut imena**. Ako aplikacija **proverava** to polje iz nekog razloga **umesto `email`** (ili bilo kog drugog atributa), možda ćete moći da **se pretvarate da ste drugi korisnici**.

U svakom slučaju, ako ste iz nekog razloga promenili svoj email, na primer na novi na koji možete pristupiti, možete **potvrditi email sa kodom koji ste primili na tu email adresu**:
```bash
aws cognito-idp verify-user-attribute \
--access-token <access_token> \
--attribute-name email --code <code> \
--region <region> --no-sign-request
```
Koristite **`phone_number`** umesto **`email`** da promenite/overite **novi broj telefona**.

> [!NOTE]
> Administrator takođe može omogućiti opciju da se **prijavite sa korisničkim imenom po izboru korisnika**. Imajte na umu da nećete moći da promenite ovu vrednost na **bilo koje korisničko ime ili preferred_username koje se već koristi** za impersonaciju drugog korisnika.

### Oporavak/Promena lozinke

Moguće je oporaviti lozinku samo **znajući korisničko ime** (ili email ili telefon se prihvata) i imati pristup jer će kod biti poslat tamo:
```bash
aws cognito-idp forgot-password \
--client-id <client_id> \
--username <username/email/phone> --region <region>
```
> [!NOTE]
> Odgovor servera će uvek biti pozitivan, kao da korisničko ime postoji. Ne možete koristiti ovu metodu za enumeraciju korisnika

Sa kodom možete promeniti lozinku sa:
```bash
aws cognito-idp confirm-forgot-password \
--client-id <client_id> \
--username <username> \
--confirmation-code <conf_code> \
--password <pwd> --region <region>
```
Da biste promenili lozinku, potrebno je da **znate prethodnu lozinku**:
```bash
aws cognito-idp change-password \
--previous-password <value> \
--proposed-password <value> \
--access-token <value>
```
## Autentifikacija

Korisnički bazen podržava **različite načine autentifikacije**. Ako imate **korisničko ime i lozinku**, takođe su podržane **različite metode** za prijavu.\
Pored toga, kada je korisnik autentifikovan u bazenu, **dodeljuju se 3 vrste tokena**: **ID token**, **Access token** i **Refresh token**.

- [**ID Token**](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-the-id-token.html): Sadrži tvrdnje o **identitetu autentifikovanog korisnika**, kao što su `ime`, `email` i `broj_telefona`. ID token se takođe može koristiti za **autentifikaciju korisnika na vašim serverskim resursima ili aplikacijama**. Morate **verifikovati** **potpis** ID tokena pre nego što možete verovati bilo kojim tvrdnjama unutar ID tokena ako ga koristite u spoljnim aplikacijama.
- ID Token je token koji **sadrži vrednosti atributa korisnika**, čak i prilagođene.
- [**Access Token**](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-the-access-token.html): Sadrži tvrdnje o autentifikovanom korisniku, listu **grupa korisnika i listu opsega**. Svrha access tokena je da **ovlasti API operacije** u kontekstu korisnika u korisničkom bazenu. Na primer, možete koristiti access token da **dodelite svom korisniku pristup** za dodavanje, promenu ili brisanje atributa korisnika.
- [**Refresh Token**](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-the-refresh-token.html): Sa refresh tokenima možete **dobiti nove ID tokene i Access tokene** za korisnika dok **refresh token nije nevažeći**. Po **defaultu**, refresh token **isteče 30 dana nakon** što se korisnik prijavi u vaš korisnički bazen. Kada kreirate aplikaciju za svoj korisnički bazen, možete postaviti isteka refresh tokena aplikacije na **bilo koju vrednost između 60 minuta i 10 godina**.

### ADMIN_NO_SRP_AUTH & ADMIN_USER_PASSWORD_AUTH

Ovo je tok autentifikacije sa servera:

- Aplikacija na serveru poziva **`AdminInitiateAuth` API operaciju** (umesto `InitiateAuth`). Ova operacija zahteva AWS kredencijale sa dozvolama koje uključuju **`cognito-idp:AdminInitiateAuth`** i **`cognito-idp:AdminRespondToAuthChallenge`**. Operacija vraća potrebne parametre za autentifikaciju.
- Nakon što aplikacija na serveru ima **parametre za autentifikaciju**, poziva **`AdminRespondToAuthChallenge` API operaciju**. `AdminRespondToAuthChallenge` API operacija uspeva samo kada obezbedite AWS kredencijale.

Ova **metoda NIJE omogućena** po defaultu.

Da biste se **prijavili**, potrebno je da znate:

- id korisničkog bazena
- id klijenta
- korisničko ime
- lozinku
- tajnu klijenta (samo ako je aplikacija konfigurisana da koristi tajnu)

> [!NOTE]
> Da biste mogli da se **prijavite ovom metodom**, ta aplikacija mora dozvoliti prijavu sa `ALLOW_ADMIN_USER_PASSWORD_AUTH`.\
> Pored toga, da biste izvršili ovu akciju, potrebni su vam kredencijali sa dozvolama **`cognito-idp:AdminInitiateAuth`** i **`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>Kod za prijavu</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

Ova metoda je još jedan jednostavan i **tradicionalni korisnički i lozinka autentifikacioni** tok. Preporučuje se da se **migrira tradicionalna** autentifikacija **na Cognito** i **preporučuje** se zatim da se **onemogući** i **koristi** metoda **ALLOW_USER_SRP_AUTH** umesto (jer ta nikada ne šalje lozinku preko mreže).\
Ova **metoda NIJE omogućena** po defaultu.

Glavna **razlika** sa **prethodnom autentifikacionom metodom** unutar koda je da **ne morate znati ID korisničkog bazena** i da **ne trebate dodatne dozvole** u Cognito korisničkom bazenu.

Da biste **se prijavili**, potrebno je da znate:

- client id
- korisničko ime
- lozinku
- client secret (samo ako je aplikacija konfigurisana da koristi tajnu)

> [!NOTE]
> Da biste **mogli da se prijavite ovom metodom**, ta aplikacija mora omogućiti prijavu sa 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 kod za prijavu</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

Ovaj scenario je sličan prethodnom, ali **umesto slanja lozinke** kroz mrežu za prijavu, **izvodi se autentifikacija izazovom** (tako da lozinka ne prolazi čak ni enkriptovana kroz mrežu).\
Ova **metoda je omogućena** po defaultu.

Da biste se **prijavili**, potrebno je da znate:

- id korisničkog bazena
- id klijenta
- korisničko ime
- lozinku
- klijentsku tajnu (samo ako je aplikacija konfigurisana da koristi tajnu)

<details>

<summary>Code to login</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

Ova **metoda će uvek biti validna** (ne može biti onemogućena) ali morate imati validan refresh token.
```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>Kod za osvežavanje</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

U ovom slučaju, **autentifikacija** će se vršiti kroz **izvršenje lambda funkcije**.

## Dodatna sigurnost

### Napredna sigurnost

Podrazumevano je onemogućena, ali ako je omogućena, Cognito bi mogao da **pronađe preuzimanje naloga**. Da biste smanjili verovatnoću, trebali biste se prijaviti sa **mreže unutar istog grada, koristeći isti korisnički agent** (i IP ako je to moguće)**.**

### **MFA Zapamti uređaj**

Ako se korisnik prijavi sa istog uređaja, MFA može biti zaobiđena, stoga pokušajte da se prijavite iz istog pregledača sa istim metapodacima (IP?) kako biste pokušali da zaobiđete MFA zaštitu.

## IAM uloge grupa korisničkog bazena

Moguće je dodati **korisnike u grupe korisničkog bazena** koje su povezane sa jednom **IAM ulogom**.\
Štaviše, **korisnici** mogu biti dodeljeni **više od 1 grupi sa različitim IAM ulogama**.

Napomena: čak i ako je grupa unutar grupe sa dodeljenom IAM ulogom, da bi mogla da pristupi IAM kredencijalima te grupe, potrebno je da **Korisnički bazen bude poveren Identitetskom bazenu** (i da zna detalje tog Identitetskog bazena).

Još jedan zahtev za dobijanje **IAM uloge navedene u IdToken-u** kada je korisnik autentifikovan u Korisničkom bazenu (`aws cognito-idp initiate-auth...`) je da **provajder autentifikacije identiteta** treba da naznači da **uloga mora biti odabrana iz tokena.**

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

**Uloge** kojima korisnik ima pristup su **unutar `IdToken`**, i korisnik može **odabrati koju ulogu želi za kredencijale** sa **`--custom-role-arn`** iz `aws cognito-identity get-credentials-for-identity`.\
Međutim, ako je **podrazumevana opcija** ona **konfigurisana** (`use default role`), i pokušate da pristupite ulozi iz IdToken-a, dobićete **grešku** (zato je potrebna prethodna konfiguracija):
```
An error occurred (InvalidParameterException) when calling the GetCredentialsForIdentity operation: Only SAML providers and providers with RoleMappings support custom role ARN.
```
> [!WARNING]
> Imajte na umu da uloga dodeljena **User Pool Group** treba da bude **dostupna od strane Identity Provider** koji **veruje User Pool** (jer će **session credentials IAM uloge biti dobijeni iz nje**).
```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}}
