Modern EDR and XDR solutions do not operate deterministically. Instead, they work in shades of gray rather than black and white, heavily relying on the correlation of events to calculate probability scores and provide meaningful insights. To ensure the effectiveness of these solutions, minimizing false positives is a critical goal. This objective requires a continuous investment in research - and deep understanding of how threat actors operate.
Being a Native XDR platform, we dedicate substantial research effort when adding new XDR sensors into our ecosystem. The development of these sensors engages not only our engineering team but also Bitdefender Labs, our in-house research institute closely connected with academia. Bitdefender Labs initiates the process with a combination of theoretical and practical research to gain a deeper insight into potential attack vectors and how threat actors operate.
During the development of our XDR sensor for Google Workspace and Google Cloud Platform, we uncovered previously unknown attack methods for escalating a compromise from a single endpoint to a network-wide breach, potentially leading to ransomware attacks or data exfiltration. Starting from a single compromised machine, threat actors could progress in several ways: they could move to other cloned machines with GCPW installed, gain access to the cloud platform with custom permissions, or decrypt locally stored passwords to continue their attack beyond the Google ecosystem.
It is important to mention that these weaknesses can be exploited only after the local machine has been compromised through other means. We responsibly disclosed these findings to Google, and they confirmed they have no plans to address these findings, as it is outside of their specific threat model. It's important to note that this isn't a matter of blame; it's a deliberate choice based on their risk assessment and security priorities. But just because certain weaknesses fall outside the scope of a threat model, it does not mean that threat actors will not exploit them. In fact, quite the opposite is true; threat actors often seek out and exploit these gaps in coverage.
GravityZone XDR includes detections of these advanced techniques. We would like to share our research for public awareness and education. By doing so, we hope to enable the wider security community to better address these issues. We are hosting a webinar with the researcher who found these novel attack methods, you can find details on how to join at the end of this report.
Google Credential Provider for Windows plays a dual role. Firstly, the GCPW enables remote Windows device management features without the need of a VPN connection of a domain registration. This Mobile Device Management (MDM) functionality is similar to Microsoft Intune and includes the ability for administrators to remotely manage and control Windows devices within their Google Workspace environment. For instance, administrators can enforce security policies, apply updates, install software, and manage device settings.
Secondly, it enables Single-Sign On (SSO) authentication to Windows operating system with Google Workspace (formerly G Suite) credentials. This provides a seamless login experience, allowing users to access their Windows devices using the same credentials they use for Gmail, Google Drive, and Google Calendar. To better understand how credential providers work in the context of the GCPW, let’s break down the process:
More information, including a GCPW demo, is available in Google Workspace Help.
Now that we've explained how GCPW uses the local privileged account 'gaia' and maintains a connection to Google APIs through the refresh token stored in the local profile, we can move on to describing the attack methods.
This is a challenge frequently encountered in virtualized environments with machine cloning, including Virtual Desktop Infrastructure (VDI) and Desktop as a Service (DaaS) solutions from companies like Citrix and VMware.
When GCPW is installed on a target machine, local ‘gaia’ account is created with a random password. The result is that while ‘gaia’ exists on all machines, each of them has a unique password. But if a machine is created by cloning another machine with pre-installed GCPW, the password is cloned as well. If you know the password to a local account, and local accounts on all machines share the same password, then you know the passwords to all machines.
This shared-password challenge is similar to having the same local administrator password on all machines that has been addressed by Microsoft’s Local Administrator Password Solution (LAPS).
To find the credentials linked to the 'gaia' user, an attacker can list the secrets stored in lsass (for example using Mimikatz) and look for the secrets with name "L$GAIA_USERNAME" and "L$GAIA_PASSWORD".
To ensure a seamless experience between the local Windows session and the broader Google ecosystem, GCPW stores an OAuth 2.0 refresh token within the session. This mechanism maintains user access without repeated authentication prompts. If this token expires, users are prompted to re-authenticate, triggering the generation of a new token.
When a threat actor gains access to a refresh OAuth token, it grants them the ability to request Access Tokens. These Access Tokens carry specific permissions, often referred to as 'scopes.' These scopes determine what actions the token can perform. Essentially, they outline the boundaries of the token's capabilities within an application or system.
For example, a scope might grant access to a user's email, calendar, or contacts. Now, with the compromised refresh token, a threat actor can request new Access Tokens with one of the scopes that is available to the compromised user (list of available scopes is included later). This means they can potentially access a wide range of user data or perform actions on the user's behalf, depending on the scopes associated with the Access Token. The refresh token is obtained at the end of the authentication process. This means that by using the refresh token to acquire an access token, we completely bypass the multi-factor authentication (MFA).
After initially focusing on the GCPW component, we later tested that the refresh token is also stored in the Google Chrome profile. As a result, this attack method doesn't necessitate the GCPW component; locally installed Google Chrome alone is sufficient for its execution.
TL;DR summary - the refresh token follows a two-step storage process. First, it's temporarily stored in the registry, and later, it finds a more permanent home under the user's Chrome profile. Decrypting it is possible from both locations, each with its own set of pros and cons. The registry approach is stealthier, offering a discreet way to access the token. However, it has a drawback—it's available for a limited time only. On the other hand, the profile-based storage method provides a more extended timeframe for access but is harder to conceal, making it a noisier option.
Full explanation - the refresh token has a dual storage journey, beginning with a temporary placement in the Windows registry and eventually finding its way into the user's Chrome profile, where it is stored for an extended period.
The initial stop for the refresh token is in the Windows registry value HKCU\SOFTWARE\Google\Accounts\<account_id>\<refresh_token>. Here, it's temporarily stored and encrypted using CryptProtectData. Strings encrypted with CryptProtectData can be decrypted using tools like Mimikatz or by calling CryptUnprotectData. CryptUnprotectData is a Windows API function used for decrypting data that has been previously encrypted with CryptProtectData. When data is encrypted using CryptProtectData, it is tied to the user's account and machine. Therefore, only processes running within the user's context can call CryptUnprotectData to retrieve the original, unencrypted data.
After its short stay in the registry, the refresh token is stored in the user's Chrome profile directory. For the default profile, this location is typically %HOME%\AppData\Local\Google\Chrome\User Data\Default. For secondary profiles, it is stored at %HOME%\AppData\Local\Google\Chrome\User Data\Profile <number>. Within a profile folder, you can find an SQLite database called Web Data. This database contains a table named token_service, where the encrypted refresh tokens associated with each profile are securely stored.
Each entry in this table consists of two columns: service and encrypted_token. To decrypt this encrypted token, you'll require an encryption key that is stored in the file %HOME%\AppData\Local\Google\Chrome\User Data\Local State. Accessing this key involves loading the associated JSON file and navigating to os_crypt->encrypted_key. Similar to the refresh token, this encryption key is also secured using CryptProtectData.
Once you've successfully decrypted this encryption key, you can proceed to decrypt your refresh token. The decryption process involves applying the Advanced Encryption Standard (AES) in Galois/Counter Mode (GCM), where the first 12 bytes represent the nonce, the final 16 bytes are the digest, and the bytes in between constitute the actual encrypted token.
If, for any reason, we cannot extract the refresh token, we can force user to re-authenticate. Following authentication with Google, GCPW updates the key HKLM\SOFTWARE\Google\GCPW\Users\<user_sid> with a value th (token handle). The token handle is used to verify the current user's session status, and it is checked each time a user attempts to log in to their computer. By changing th to an invalid value or deleting it, we can force GCPW to reauthenticate the user the next time they start or unlock their computer.
Once we have the refresh token, the next step involves the use of application credentials to construct a POST request for issuing an access token. These application credentials are same for both Google Chrome and GCPW, and they follow the OAuth standard, requiring two key attributes - client_id and client_secret. It's important to note that while we will not publish their values, they are not considered a well-guarded secret, as they can be readily extracted directly from executables or the Chromium source code, and they are not unique to a specific machine.
With these attributes at hand, we can create the POST request, including the following key elements:
- client_id: This is a unique identifier for the application.
- client_secret: It's another identifier, typically known only to the application itself.
- grant_type: “refresh_token”
- refresh_token: The refresh token obtained earlier.
- scope: This attribute defines the permissions or 'scopes' granted to the access token.
This POST request can then be sent to the API endpoint https://www.googleapis.com/oauth2/v4/token. This endpoint will then issue the access token, providing the user or threat actor with the necessary access to the Google API.
Threat actors can access wide range of Google APIs, the partial list is available below:
The list of available endpoints to the threat actor represents a wide range of permissions and access. Here are some potential ways these accesses could be abused:
Access tokens, when stolen, pose a security risk by allowing attackers to gain limited access within the boundaries defined by the token's permissions. These tokens are often time-bound and come with specific scope restrictions. In contrast, having access to plaintext credentials, such as usernames and passwords, represents a more severe threat. This is because it enables attackers to directly impersonate legitimate users and gain unrestricted access to their accounts, potentially leading to complete account takeover. Access to plaintext credentials is generally considered a more serious security concern.
By default, GCPW saves the user’s password as an encrypted LSA secret. This is used for password resetting functionality.
The value of the secret Chrome-GCPW-<User_SID> is a JSON that includes the encrypted password and the resource ID of the key that was used for encryption. These encryption keys are managed by Google, and only the account owner can retrieve them.
Now, by combining the previous exploit with this one, an attacker could first generate a valid access token with the scope https://www.google.com/accounts/OAuthLogin. With this access token in hand, the attacker can send a GET request to https://devicepasswordescrowforwindows-pa.googleapis.com/v1/getprivatekey/<resource_id > (undocumented API endpoint).
The response to this request will contain the private RSA key that is required to decrypt the password field. The password field's format is as follows:
This method allows the attacker to gain access to and decrypt the user's password.
The identified attack methods for Google Workspace pose a security risk, but it's important to note that they require the compromise of a local device first.
Password recovery attempt displayed in the Incident Advisor.
GravityZone XDR already includes detections of these advanced techniques. These detections are labeled GoogleWorkspacePasswordRecoveryAttempted, GoogleWorkspaceRefreshTokenAccessed, GoogleWorkspaceLogoutForced.
Complex kill chain displayed in the Extended Root Cause Analysis view.
Join our upcoming webinar where we will discuss these attack methods in detail with the researcher who initially identified them. During the webinar, we will share best practices and recommendations for improving your organization's security posture in the face of evolving threats.
tags
Martin is technical solutions director at Bitdefender. He is a passionate blogger and speaker, focusing on enterprise IT for over two decades. He loves travel, lived in Europe, Middle East and now residing in Florida.
View all postsDon’t miss out on exclusive content and exciting announcements!