Solving GCP Pentest Lab CTF

GCP-Pentest-Lab is a vulnerable environment designed to explore and exploit GCP misconfigurations. This project contains different misconfigurations (with six flags), and the flags have no specific format. Players start as random users through a web application and must find their way through various security flaws without relying on traditional web or OS-level exploits.

Table of Contents

Setup

Go to any command line (Linux preferred). Configure your Google Cloud account as given in the initial steps of this lab.

First, clone the GitHub repository.

We can see the terraform files in it that we need to run to spin up this lab.

terraform init
terraform apply

While deploying, enter the project ID of the GCP project you will use to run this lab.

Note: For this blog post, we are deploying on a GCP project named cloudsecurityclub-gcp

We get a public IP of the VM, which is the entry point to the labs.

Flag-1

Description: Flag 1 is in an open bucket

Solution:

Let’s try visiting the IP address from the output in the browser.

The images on this website are hosted on GCP buckets. The name of the bucket is cloudsecurityclub-gcp-prod-bucket.

We can see if the bucket is misconfigured to list the contents of the bucket.

https://storage.googleapis.com/storage/v1/b/cloudsecurityclub-gcp-prod-bucket/o

When we tried to do so, we got an error message saying the user didn’t have the .list permission on the resource. In simple terms, the objects in this bucket can be public, but the bucket doesn’t list all the objects in it.

However, the Flag 1 description says it is an open bucket. Let’s see if other images are hosted elsewhere. 

In one of the images on the website, we can see that the bucket name (cloudsecurityclub-gcp-dev-bucket) differs from the previous bucket we found.

We will see if this bucket is misconfigured and lists all the objects.

https://storage.googleapis.com/storage/v1/b/cloudsecurityclub-dev-dev-bucket/o

We can see the list of all the objects in this public “dev” bucket. 

Now, we will analyze all the objects.

We can see this object named flag1.txt. We will download it using the mediaLink given.

Just click on that mediaLink URL or paste it into the browser.

The downloaded file has our first flag.

Flag-2

Description: Flag 2 is in another bucket, but this one isn’t public 🙂

Solution:

From the objects in the same cloudsecurityclub-gcp-dev-bucket, we find another interesting file – sync_sa_key.json.

Upon downloading it in the same way as above, we got the below key.

The service account file contains base64 content. We will decode this base64 string and rename it as decoded_sync_sa_key.json.

Now, we will activate the service account with this decoded key.

Now, we will list the buckets using this service account.

gsutil ls

We now will list the content of cloudsecurityclub-gcp-secret-bucket.

This shows that this bucket has flag2.txt.

We got the second flag.

Also, when we list the content of the other secret-secret bucket, we can see that this bucket has flag-6.txt.

We got an error when copying this flag-6.txt from this bucket.

We’ll get back to it later. We will go to find the next flag now.

Flag-3

Description: “Flag 3 is sitting inside some source code.”

Solution:

We will access the web application’s source code by SSHing into the virtual machine.

For that, first, we will set the public ssh-key into the metadata of the compute instance. Then we will try to ssh into the instance and search for the source code there.

We will generate the ssh-key:

ssh-keygen -t rsa -b 4096

We will keep the name of the SSH key as ssh-key-gcp

We can see that SSH private key and public key are created.

We will set this public key in the metadata of the compute instance and use the private key to ssh into the instance. 

We will now add the SSH key to the metadata of the instance

gcloud compute instances add-metadata cloudsecurityclub-gcp-flask-vm 
--metadata=ssh-keys="ubuntu:<ssh-key-gcp.pub> ubuntu" --zone=us-east4-a

NOTE: You can check the name of the instance and the zone by listing the compute instances - gcloud compute instances list

Now, we will use the private key to SSH into the instance.

ssh -i <private-key> username@<external_ip_address>

We are inside the compute instance now. We can see the machine’s name, which is also the name of the compute instance.

Inside the /etc folder, we can see the gcp-pentest-flask-app folder.

Getting into that folder and listing the contents of it

We can see app.py inside it. 

Since the flag-3 description states that the flag is in some source code, let’s explore the source code.

We found the third flag in the source code comments. 

Now, we will move to the fourth flag.

Flag-4

Description: “Flag 4 is a secret, literally!”

Solution:

The first thing someone can think of regarding GCP infrastructure is the secret manager, as they store confidential information (secrets, in other words). 

Let’s see if the VM’s default access token has access to list and fetch secrets from the secret manager. First, we get the access token.

curl -H 'Metadata-Flavor: Google' http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
export ACCESS_TOKEN_DEFAULT_SA=<token>

We will try to access the secret manager by requesting the URL below with the access token of the default service account.

curl -H "Authorization: Bearer $ACCESS_TOKEN_DEFAULT_SA" "https://secretmanager.googleapis.com/v1/projects/cloudsecurityclub-gcp/secrets" 

The output says an entry in the secret manager with the name flag-4. We will try to access it.

We will again make a curl request on the URL below, appending the secret name flag-4. Every secret can have multiple versions. Using the latest will fetch the contents of the most recent version. Also, we must use the access method to get the data stored in the secret manager. 

Our final curl command looks like the following:

curl "https://secretmanager.googleapis.com/v1/projects/cloudsecurityclub-gcp/secrets/flag-4/versions/latest:access"  --header "Authorization: Bearer $ACCESS_TOKEN_DEFAULT_SA"  

The data for flag 4 is visible and in a base64-encoded format. Let’s decode it.

We have found the fourth flag.

Flag-5

Description: “Flag 5 is inside some instance but isn’t a file! “

Solution:

Let’s see if there’s any juicy information in the instance’s metadata. 

We can see that this service account we got from cloudsecurityclub-gcp-dev-bucket is currently active on my local system.

gcloud auth list

First, we will list the compute instance with the help of this service account.

gcloud compute instances list

We can see the instance’s name and zone from the above information.

First, we will set the access token of the service account we activated from the key we got from the dev bucket into the environment variable ACCESS_TOKEN.

export ACCESS_TOKEN=$(gcloud auth print-access-token)

We will pass it on to the curl request we will make next to retrieve the metadata.

export METADATA=$(curl -H "Authorization: Bearer $ACCESS_TOKEN" "https://www.googleapis.com/compute/v1/projects/cloudsecurityclub-gcp/zones/us-east4-a/instances/cloudsecurityclub-gcp-flask-vm?fields=metadata")

We can see the request was successful, and we received the response.

echo $METADATA | jq

We got the 5th flag stored in the startup script in the compute instance’s metadata.

Flag-6

Description: “Flag 6 is in yet another bucket, but this one is the most restricted yet!”

Solution:

While getting the second flag, we saw a super-secret bucket containing the flag6 file.

We will try to access that bucket using the default service account’s access token for the compute instance.

curl -H 'Metadata-Flavor: Google' http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token

We got the access token of the default service account.

We will use this access token to see if we can access the flag6 object in the super secret bucket.

curl -H "Authorization: Bearer $ACCESS_TOKEN_DEFAULT_SA" "https://storage.googleapis.com/storage/v1/b/cloudsecurityclub-gcp-super-secret-bucket/o/flag6.txt?alt=media"

Finally, we found the 6th flag.

Reply

or to participate.