$5k Service dependencies

Before getting to the bug itself, you should at least read the "Key concepts" part of this other bug, it will be useful for understanding this one.

The bug
The services in the Google Service Management API have several settings that developers can set, which can be done by crafting a Service object, pushing it with the create or submit methods, and then rolling it out so the settings can take effect.
Among those settings, there are usage settings (Like requirements a consumer must satisfy or rules for calling some methods), and among the usage settings I discovered, on November 18th, 2016, a hidden option called "dependsOnServices" (Which should only be accessible by Google internal clients) documented as an array of strings with the following description:
Services that must be activated in order for this service to be used.
The set of services activated as a result of these relations are all
activated in parallel with no guaranteed order of activation.
Each string is a service name, e.g. `calendar.googleapis.com`.

It sounded like a very interesting option, so I tested it with the Google Cloud Console client by sending the following request, rolling the configuration and then enabling my service on one of my projects:
POST /v1/services/<SERVICE NAME>/configs?key=AIzaSyCI-zsRP85UVOi0DjtiCwWBwQ1djDy741g HTTP/1.1 Host: servicemanagement.clients6.google.com Authorization: SAPISIDHASH <SAPISIDHASH> X-Origin: https://console.cloud.google.com Cookie: <GOOGLE COOKIES> Content-Length: <CONTENT-LENGTH>
{
  "name": "<SERVICE NAME>",
  "producerProjectId": "<PROJECT>",
  "configVersion": 3,
  "usage": {
    "dependsOnServices": [
      ...<SERVICES>...
    ]
  }

}

After a little testing I quickly understood how it works: Every time I enable my service on a project, each one of the services named in "usage.dependsOnServices" will be enabled too as long as the project satisfies the usage requirements of those services  (For instance, billing enabled for the "compute.googleapis.com" service).
That may seem harmless, but I discovered an important flaw in that logic: It is never checked whether the user has been given permission to enable the service ("servicemanagement.services.bind"), so an attacker could bypass the authorization check usually done and enable other's services without their permission (And probably without their knowledge either).
Note: Among the private services available, there are some private Google APIs too, that are only meant for internal use, in development (Including staging and test versions) or only for a few white-listed users (Trusted Testers, Google My Business API, etc.). This is a very big deal since those APIs might not be subject to the same security standards as public Google APIs, and may have flaws that allow very dangerous attacks.

After my original report, Google rewarded me $5000 (After successfully demonstrating I could enable and access private internal Google APIs), and one day I got the following email:

I did as the message said, and checked whether I could replicate th bug, and I couldn't do it through the original vector (Using the Google Cloud Console client) because it no longer had access to the field, but knowing that any client with the proper visibility access would be able to set the field I checked with the Firebase client, and, surprisingly, it did not only had access to the field, but the bug worked flawlessly as reported.
After that, Google blocked the access to the field of the Firebase client, but not of other clients, and also I found a much better approach that allowed any client to set the field:
Using the submit configuration method I could also set the "usage.dependsOnServices", and it worked regardless of the client having or not access to the field through the API (Since the field was set in the file given to the method, which is checked differently).
About a month after reporting the new vector, I asked Google how was it going and this was their response:

It took a while, but a few months later they implemented an internal validator at the submit configuration method that successfully blocked this way to set the field, despite that, it took until March 2018 to finally fix the original vector for all clients with access to the field (It was fixed by deprecating the "usage.dependsOnServices" field, so it can still be set, it just won't have any effect at all when enabling a service).

Timeline (UTC-3)

  • 2016-11-18 Initial submission and triage
  • 2016-12-06 - Google Security team waiting on the product team to make a reward decision
  • 2016-12-13 - Working example of the bug requested (And given)
  • 2017-01-10 - A reward of 5000 dollars is issued
  • 2017-05-05 - Bug "fixed" and verified by a Google security engineer
  • 2017-05-08 - Sent example of bug still working with the Firebase client
  • 2017-05-20 - Discovered and reported the "submit method" vector
  • 2017-06-15 - Asked how was the fix going
  • 2017-06-19 - Google replied they were investigating ways to fix the "submit method" vector, but it was tricky
  • A few months later - "Submit method" vector fixed
  • March 2018 - "usage.dependsOnServices" field deprecated, thus, fixed

Comments