Cognito User Pools

Support HackTricks

Basic Information

사용자 풀은 Amazon Cognito의 사용자 디렉토리입니다. 사용자 풀을 사용하면 사용자가 Amazon Cognito를 통해 웹 또는 모바일 앱에 로그인하거나 제3자 신원 제공자(IdP)를 통해 연합할 수 있습니다. 사용자가 직접 로그인하든 제3자를 통해 로그인하든, 사용자 풀의 모든 구성원은 SDK를 통해 액세스할 수 있는 디렉토리 프로필을 가지고 있습니다.

사용자 풀은 다음을 제공합니다:

  • 가입 및 로그인 서비스.

  • 사용자를 로그인시키기 위한 내장된 사용자 정의 웹 UI.

  • Facebook, Google, Amazon 로그인, Apple 로그인 및 사용자 풀의 SAML 및 OIDC 신원 제공자를 통한 소셜 로그인.

  • 사용자 디렉토리 관리 및 사용자 프로필.

  • 다단계 인증(MFA), 손상된 자격 증명 확인, 계정 탈취 보호, 전화 및 이메일 확인과 같은 보안 기능.

  • AWS Lambda 트리거를 통한 사용자 마이그레이션 및 사용자 정의 워크플로우.

응용 프로그램의 소스 코드는 일반적으로 사용자 풀 ID클라이언트 응용 프로그램 ID(때때로 응용 프로그램 비밀?)를 포함하고 있으며, 이는 사용자가 Cognito 사용자 풀에 로그인하는 데 필요합니다.

Potential attacks

  • 등록: 기본적으로 사용자는 자신을 등록할 수 있으므로 자신을 위한 사용자를 생성할 수 있습니다.

  • 사용자 열거: 등록 기능을 사용하여 이미 존재하는 사용자 이름을 찾을 수 있습니다. 이 정보는 무차별 대입 공격에 유용할 수 있습니다.

  • 로그인 무차별 대입: 인증 섹션에는 사용자가 로그인하는 데 필요한 모든 방법이 나와 있으며, 이를 통해 유효한 자격 증명을 찾기 위해 무차별 대입을 시도할 수 있습니다.

Tools for pentesting

  • Pacu는 이제 계정의 모든 Cognito 자산을 열거하고 약한 구성, 액세스 제어에 사용되는 사용자 속성 등을 플래그하는 cognito__enumcognito__attack 모듈을 포함합니다. 또한 MFA 지원을 포함한 사용자 생성 및 수정 가능한 사용자 정의 속성, 사용 가능한 신원 풀 자격 증명, ID 토큰의 수용 가능한 역할에 기반한 권한 상승을 자동화합니다. 모듈 기능에 대한 설명은 블로그 게시물 2부를 참조하십시오. 설치 지침은 주요 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는 원치 않는 계정 생성 및 계정 오라클을 포함하여 Cognito에 대한 다양한 공격을 구현하는 파이썬 CLI 도구입니다. 자세한 내용은 이 링크를 확인하세요.

# Install
pip install cognito-scanner
# Run
cognito-scanner --help
  • CognitoAttributeEnum: 이 스크립트는 사용자에 대한 유효한 속성을 열거할 수 있습니다.

python cognito-attribute-enu.py -client_id 16f1g98bfuj9i0g3f8be36kkrl

등록

User Pools는 기본적으로 새 사용자를 등록할 수 있도록 허용합니다.

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

누구나 등록할 수 있는 경우

사용자에 대한 자세한 정보를 제공해야 한다는 오류 메시지를 볼 수 있습니다:

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

당신은 다음과 같은 JSON으로 필요한 세부정보를 제공할 수 있습니다:

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

이 기능을 사용하여 기존 사용자를 열거할 수도 있습니다. 해당 이름으로 사용자가 이미 존재할 때의 오류 메시지는 다음과 같습니다:

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

이전 명령에서 사용자 정의 속성이 "custom:"으로 시작하는지 주목하세요. 또한 등록할 때 사용자에게 새로운 사용자 정의 속성을 생성할 수 없다는 점을 알아두세요. 기본 속성(필수 속성이 아니더라도)과 지정된 사용자 정의 속성에만 값을 제공할 수 있습니다.

또는 클라이언트 ID가 존재하는지 테스트하기 위해서입니다. 클라이언트 ID가 존재하지 않을 경우의 오류는 다음과 같습니다:

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

관리자가 사용자 등록만 가능할 경우

이 오류가 발생하며 사용자를 등록하거나 열거할 수 없습니다:

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

Verifying Registration

Cognito는 새 사용자를 이메일 또는 전화번호로 확인하여 검증할 수 있습니다. 따라서 사용자를 생성할 때 일반적으로 최소한 사용자 이름과 비밀번호와 함께 이메일 및/또는 전화번호가 필요합니다. 당신이 제어하는 하나를 설정하면 이렇게 새로 생성된 사용자 계정확인하기 위한 코드를 받을 수 있습니다:

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

비록 같은 이메일과 전화번호를 사용할 수 있는 것처럼 보이지만, 생성된 사용자를 확인해야 할 때 Cognito는 같은 정보를 사용했다고 불평하며 계정을 확인할 수 없게 됩니다.

권한 상승 / 속성 업데이트

기본적으로 사용자는 자신의 속성 값을 수정할 수 있습니다:

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

사용자 정의 속성 권한 상승

사용자 정의 속성(예: isAdmin)이 사용되고 있을 수 있습니다. 기본적으로 자신의 속성 값을 변경할 수 있으므로, 값을 직접 변경하여 권한을 상승시킬 수 있습니다!

이메일/사용자 이름 수정 권한 상승

사용자의 이메일 및 전화번호를 수정하는 데 사용할 수 있지만, 계정이 확인된 상태로 유지되더라도 해당 속성은 확인되지 않은 상태로 설정됩니다(다시 확인해야 함).

이메일이나 전화번호로 로그인할 수 없지만, 사용자 이름으로 로그인할 수 있습니다. 이메일이 수정되었고 확인되지 않았더라도 email 필드 내의 ID 토큰에 나타나며, email_verified 필드는 false가 됩니다. 그러나 앱이 그것을 확인하지 않는다면 다른 사용자를 가장할 수 있습니다.

또한, 이름 속성을 수정하여 name 필드에 무엇이든 넣을 수 있다는 점에 유의하십시오. 어떤 이유로 앱이 email(또는 다른 속성) 대신 해당 필드를 확인하고 있다면, 다른 사용자를 가장할 수 있습니다.

어쨌든, 어떤 이유로 이메일을 새 이메일로 변경한 경우, 해당 이메일 주소로 받은 코드로 이메일을 확인할 수 있습니다:

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

전화번호 대신 **이메일**을 사용하여 새 전화번호를 변경/확인합니다.

관리자는 사용자가 선호하는 사용자 이름으로 로그인하는 옵션을 활성화할 수도 있습니다. 이 값을 다른 사용자를 가장하기 위해 이미 사용 중인 사용자 이름이나 선호하는 사용자 이름으로 변경할 수 없다는 점에 유의하십시오.

비밀번호 복구/변경

사용자 이름(또는 이메일 또는 전화번호)을 알고 있고, 그곳으로 코드가 전송되므로 접근할 수 있다면 비밀번호를 복구하는 것이 가능합니다:

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

서버의 응답은 항상 긍정적일 것이며, 마치 사용자 이름이 존재하는 것처럼 보입니다. 이 방법을 사용하여 사용자를 열거할 수 없습니다.

코드를 사용하여 비밀번호를 변경할 수 있습니다:

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

비밀번호를 변경하려면 이전 비밀번호를 알아야 합니다:

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

인증

사용자 풀은 다양한 인증 방법을 지원합니다. 사용자 이름과 비밀번호가 있는 경우에도 다양한 방법으로 로그인할 수 있습니다. 또한, 사용자가 풀에서 인증되면 3가지 유형의 토큰이 제공됩니다: ID 토큰, 액세스 토큰, 리프레시 토큰입니다.

  • ID 토큰: 인증된 사용자의 신원에 대한 주장을 포함하며, name, email, phone_number와 같은 정보를 포함합니다. ID 토큰은 리소스 서버 또는 서버 애플리케이션에 사용자 인증을 위해 사용할 수도 있습니다. 외부 애플리케이션에서 사용할 경우 ID 토큰 내부의 주장을 신뢰하기 전에 서명검증해야 합니다.

  • ID 토큰은 사용자의 속성 값을 포함하는 토큰으로, 사용자 정의 속성도 포함됩니다.

  • 액세스 토큰: 인증된 사용자에 대한 주장, 사용자의 그룹 목록, 범위 목록을 포함합니다. 액세스 토큰의 목적은 사용자 풀 내에서 API 작업을 승인하는 것입니다. 예를 들어, 액세스 토큰을 사용하여 사용자에게 사용자 속성을 추가, 변경 또는 삭제할 수 있는 권한을 부여할 수 있습니다.

  • 리프레시 토큰: 리프레시 토큰을 사용하면 사용자를 위한 새로운 ID 토큰과 액세스 토큰을 얻을 수 있습니다. 리프레시 토큰이 유효하지 않을 때까지 가능합니다. 기본적으로, 리프레시 토큰은 사용자가 사용자 풀에 로그인한 후 30일 후에 만료됩니다. 사용자 풀에 대한 애플리케이션을 생성할 때 애플리케이션의 리프레시 토큰 만료를 60분에서 10년 사이의 값으로 설정할 수 있습니다.

ADMIN_NO_SRP_AUTH & ADMIN_USER_PASSWORD_AUTH

서버 측 인증 흐름은 다음과 같습니다:

  • 서버 측 애플리케이션이 AdminInitiateAuth API 작업을 호출합니다 (대신 InitiateAuth). 이 작업은 cognito-idp:AdminInitiateAuthcognito-idp:AdminRespondToAuthChallenge 권한이 포함된 AWS 자격 증명이 필요합니다. 이 작업은 필요한 인증 매개변수를 반환합니다.

  • 서버 측 애플리케이션이 인증 매개변수를 얻은 후, AdminRespondToAuthChallenge API 작업을 호출합니다. AdminRespondToAuthChallenge API 작업은 AWS 자격 증명을 제공할 때만 성공합니다.

방법은 기본적으로 활성화되어 있지 않습니다.

로그인하려면 다음 정보를 알아야 합니다:

  • 사용자 풀 ID

  • 클라이언트 ID

  • 사용자 이름

  • 비밀번호

  • 클라이언트 비밀 (앱이 비밀을 사용하도록 구성된 경우에만)

이 방법으로 로그인할 수 있으려면 해당 애플리케이션이 ALLOW_ADMIN_USER_PASSWORD_AUTH로 로그인할 수 있도록 허용해야 합니다. 또한, 이 작업을 수행하려면 cognito-idp:AdminInitiateAuthcognito-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
로그인 코드

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

이 방법은 또 다른 간단하고 **전통적인 사용자 및 비밀번호 인증** 흐름입니다. **전통적인** 인증 방법을 **Cognito로 마이그레이션**하는 것이 권장되며, 이후에는 이를 **비활성화**하고 **ALLOW\_USER\_SRP\_AUTH** 방법을 대신 **사용하는 것이 권장**됩니다(이 방법은 비밀번호를 네트워크로 전송하지 않기 때문입니다).\
이 **방법은 기본적으로 활성화되어 있지 않습니다**.

코드 내에서 **이전 인증 방법**과의 주요 **차이점**은 **사용자 풀 ID를 알 필요가 없고**, Cognito 사용자 풀에서 **추가 권한이 필요하지 않다는 점**입니다.

**로그인**하려면 **알아야 하는 것**:

* 클라이언트 ID
* 사용자 이름
* 비밀번호
* 클라이언트 비밀(앱이 비밀을 사용하도록 구성된 경우에만)

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

이 방법으로 **로그인할 수 있으려면** 해당 애플리케이션이 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

방법은 항상 유효합니다 (비활성화할 수 없습니다) 하지만 유효한 리프레시 토큰이 필요합니다.

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

Last updated