# GCP <--> Workspace Pivoting

{{#include ../../../banners/hacktricks-training.md}}

## **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**.

> [!NOTE]
> This basically means that **service accounts** inside GCP projects of an organization might be able to i**mpersonate Workspace users** of the same organization (or even from a different one).

For more information about how this exactly works check:

{{#ref}}
gcp-understanding-domain-wide-delegation.md
{{#endref}}

### 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**.

> [!CAUTION]
> 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.

#### [GCP Generate Delegation Token](https://github.com/carlospolop/gcp_gen_delegation_token)

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`:

```bash
# 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"
```

#### [**DelePwn**](https://github.com/n0tspam/delepwn)

Based on the following DeleFriend tool, but with some additions like the ability to enumerate the domain, drive, gmail, calendar and perform other operations.

#### [**DeleFriend**](https://github.com/axon-git/DeleFriend)

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 t**arget 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's Python script](https://gitlab.com/gitlab-com/gl-security/threatmanagement/redteam/redteam-public/gcp_misc/-/blob/master/gcp_delegation.py)

Gitlab've created [this Python script](https://gitlab.com/gitlab-com/gl-security/gl-redteam/gcp_misc/blob/master/gcp_delegation.py) 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:

```bash
# 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 \
    --list

# 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**](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**](https://developers.google.com/identity/protocols/oauth2/scopes), 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.

> [!CAUTION]
> 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).

```bash
# 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>

# FROM HERE THE USER NEEDS TO HAVE ENOUGH WORKSPACE ACCESS
gcloud beta identity groups preview --customer <org-cust-id>
```

Check **more enumeration in**:

{{#ref}}
../gcp-services/gcp-iam-and-org-policies-enum.md
{{#endref}}

### Abusing Gcloud credentials

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

{{#ref}}
../gcp-persistence/gcp-non-svc-persistence.md
{{#endref}}

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:

```bash
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'`**:

<figure><img src="../../../images/image (342).png" alt="" width="563"><figcaption></figcaption></figure>

> [!WARNING]
> 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/](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.

### References

- [https://www.hunters.security/en/blog/delefriend-a-newly-discovered-design-flaw-in-domain-wide-delegation-could-leave-google-workspace-vulnerable-for-takeover](https://www.hunters.security/en/blog/delefriend-a-newly-discovered-design-flaw-in-domain-wide-delegation-could-leave-google-workspace-vulnerable-for-takeover)

{{#include ../../../banners/hacktricks-training.md}}


