GCP <--> Workspace Pivoting

Support HackTricks

From GCP to GWS

Domain Wide Delegation basics

Google Workspace's Domain-Wide delegation allows an identity object, either an external app from Google Workspace Marketplace or an internal GCP Service Account, to access data across the Workspace on behalf of users.

This basically means that service accounts inside GCP projects of an organization might be able to impersonate Workspace users of the same organization (or even from a different one).

For more information about how this exactly works check:

GCP - Understanding Domain-Wide Delegation

Compromise existing delegation

If an attacker compromised some access over GCP and known a valid Workspace user email (preferably super admin) of the company, he could enumerate all the projects he has access to, enumerate all the SAs of the projects, check to which service accounts he has access to, and repeat all these steps with each SA he can impersonate. With a list of all the service accounts he has access to and the list of Workspace emails, the attacker could try to impersonate user with each service account.

Note that when configuring the domain wide delegation no Workspace user is needed, therefore just know one valid one is enough and required for the impersonation. However, the privileges of the impersonated user will be used, so if it's Super Admin you will be able to access everything. If it doesn't have any access this will be useless.

This simple script will generate an OAuth token as the delegated user that you can then use to access other Google APIs with or without gcloud:

# Impersonate indicated user
python3 gen_delegation_token.py --user-email <user-email> --key-file <path-to-key-file>

# Impersonate indicated user and add additional scopes
python3 gen_delegation_token.py --user-email <user-email> --key-file <path-to-key-file> --scopes "https://www.googleapis.com/auth/userinfo.email, https://www.googleapis.com/auth/cloud-platform, https://www.googleapis.com/auth/admin.directory.group, https://www.googleapis.com/auth/admin.directory.user, https://www.googleapis.com/auth/admin.directory.domain, https://mail.google.com/, https://www.googleapis.com/auth/drive, openid"

This is a tool that can perform the attack following these steps:

  1. Enumerate GCP Projects using Resource Manager API.

  2. Iterate on each project resource, and enumerate GCP Service account resources to which the initial IAM user has access using GetIAMPolicy.

  3. Iterate on each service account role, and find built-in, basic, and custom roles with serviceAccountKeys.create permission on the target service account resource. It should be noted that the Editor role inherently possesses this permission.

  4. Create a new KEY_ALG_RSA_2048 private key to each service account resource which is found with relevant permission in the IAM policy.

  5. Iterate on each new service account and create a JWT object for it which is composed of the SA private key credentials and an OAuth scope. The process of creating a new JWT object will iterate on all the existing combinations of OAuth scopes from oauth_scopes.txt list, in order to find all the delegation possibilities. The list oauth_scopes.txt is updated with all of the OAuth scopes we’ve found to be relevant for abusing Workspace identities.

  6. The _make_authorization_grant_assertion method reveals the necessity to declare a target workspace user, referred to as subject, for generating JWTs under DWD. While this may seem to require a specific user, it's important to realize that DWD influences every identity within a domain. Consequently, creating a JWT for any domain user affects all identities in that domain, consistent with our combination enumeration check. Simply put, one valid Workspace user is adequate to move forward. This user can be defined in DeleFriend’s config.yaml file. If a target workspace user is not already known, the tool facilitates the automatic identification of valid workspace users by scanning domain users with roles on GCP projects. It's key to note (again) that JWTs are domain-specific and not generated for every user; hence, the automatic process targets a single unique identity per domain.

  7. Enumerate and create a new bearer access token for each JWT and validate the token against tokeninfo API.

Gitlab've created this Python script that can do two things - list the user directory and create a new administrative account while indicating a json with SA credentials and the user to impersonate. Here is how you would use it:

# Install requirements
pip install --upgrade --user oauth2client

# Validate access only
./gcp_delegation.py --keyfile ./credentials.json \
    --impersonate steve.admin@target-org.com \
    --domain target-org.com

# List the directory
./gcp_delegation.py --keyfile ./credentials.json \
    --impersonate steve.admin@target-org.com \
    --domain target-org.com \

# Create a new admin account
./gcp_delegation.py --keyfile ./credentials.json \
    --impersonate steve.admin@target-org.com \
    --domain target-org.com \
    --account pwned

Create a new delegation (Persistence)

It's possible to check Domain Wide Delegations in https://admin.google.com/u/1/ac/owl/domainwidedelegation.

An attacker with the ability to create service accounts in a GCP project and super admin privilege to GWS could create a new delegation allowing SAs to impersonate some GWS users:

  1. Generating a New Service Account and Corresponding Key Pair: On GCP, new service account resources can be produced either interactively via the console or programmatically using direct API calls and CLI tools. This requires the role iam.serviceAccountAdmin or any custom role equipped with the iam.serviceAccounts.create permission. Once the service account is created, we'll proceed to generate a related key pair (iam.serviceAccountKeys.create permission).

  2. Creation of new delegation: It's important to understand that only the Super Admin role possesses the capability to set up global Domain-Wide delegation in Google Workspace and Domain-Wide delegation cannot be set up programmatically, It can only be created and adjusted manually through the Google Workspace console.

    • The creation of the rule can be found under the page API controls → Manage Domain-Wide delegation in Google Workspace Admin console.

  3. Attaching OAuth scopes privilege: When configuring a new delegation, Google requires only 2 parameters, the Client ID, which is the OAuth ID of the GCP Service Account resource, and OAuth scopes that define what API calls the delegation requires.

    • The full list of OAuth scopes can be found here, but here is a recommendation: https://www.googleapis.com/auth/userinfo.email, https://www.googleapis.com/auth/cloud-platform, https://www.googleapis.com/auth/admin.directory.group, https://www.googleapis.com/auth/admin.directory.user, https://www.googleapis.com/auth/admin.directory.domain, https://mail.google.com/, https://www.googleapis.com/auth/drive, openid

  4. Acting on behalf of the target identity: At this point, we have a functioning delegated object in GWS. Now, using the GCP Service Account private key, we can perform API calls (in the scope defined in the OAuth scope parameter) to trigger it and act on behalf of any identity that exists in Google Workspace. As we learned, the service account will generate access tokens per its needs and according to the permission he has to REST API applications.

    • Check the previous section for some tools to use this delegation.

Cross-Organizational delegation

OAuth SA ID is global and can be used for cross-organizational delegation. There has been no restriction implemented to prevent cross-global delegation. In simple terms, service accounts from different GCP organizations can be used to configure domain-wide delegation on other Workspace organizations. This would result in only needing Super Admin access to Workspace, and not access to the same GCP account, as the adversary can create Service Accounts and private keys on his personally controlled GCP account.

Creating a Project to enumerate Workspace

By default Workspace users have the permission to create new projects, and when a new project is created the creator gets the Owner role over it.

Therefore, a user can create a project, enable the APIs to enumerate Workspace in his new project and try to enumerate it.

In order for a user to be able to enumerate Workspace he also needs enough Workspace permissions (not every user will be able to enumerate the directory).

# Create project
gcloud projects create <uniq-projec-name> --name=proj-name
# Set project
gcloud config set project <uniq-projec-name>
# Enable svcs
gcloud services enable admin.googleapis.com
gcloud services enable cloudidentity.googleapis.com
# Get org ID
gcloud organizations list
# Get currents email user groups (at least you can check the groups and members of the groups you belong to)
gcloud identity groups memberships search-transitive-groups --member-email <email> --labels=cloudidentity.googleapis.com/groups.discussion_forum
gcloud identity groups memberships list --group-email=g<group-email>

gcloud beta identity groups preview --customer <org-cust-id>

Check more enumeration in:

GCP - IAM, Principals & Org Policies Enum

Abusing Gcloud

You can find further information about the gcloud flow to login in:

GCP - Non-svc Persistance

As explained there, gcloud can request the scope https://www.googleapis.com/auth/drive which would allow a user to access the drive of the user. As an attacker, if you have compromised physically the computer of a user and the user is still logged with his account you could login generating a token with access to drive using:

gcloud auth login --enable-gdrive-access

If an attacker compromises the computer of a user he could also modify the file google-cloud-sdk/lib/googlecloudsdk/core/config.py and add in the CLOUDSDK_SCOPES the scope 'https://www.googleapis.com/auth/drive':

Therefore, the next time the user logs in he will create a token with access to drive that the attacker could abuse to access the drive. Obviously, the browser will indicate that the generated token will have access to drive, but as the user will call himself the gcloud auth login, he probably won't suspect anything.

To list drive files: curl -H "Authorization: Bearer $(gcloud auth print-access-token)" "https://www.googleapis.com/drive/v3/files"

From GWS to GCP

Access privileged GCP users

If an attacker has complete access over GWS he will be able to access groups with privilege access over GCP or even users, therefore moving from GWS to GCP is usually more "simple" just because users in GWS have high privileges over GCP.

Google Groups Privilege Escalation

By default users can freely join Workspace groups of the Organization and those groups might have GCP permissions assigned (check your groups in https://groups.google.com/).

Abusing the google groups privesc you might be able to escalate to a group with some kind of privileged access to GCP.


Support HackTricks

Last updated