原文链接:https://www.ezequiel.tech/p/75k-google-services-mix-up.html*
在讨论漏洞细节之前,我需要向大家解释一些概念,如果不需要,可自行跳过。
前导知识
Google 有一项名为Google Service Management的服务,它提供了一种方法来管理使用 Google 系统的服务 (API) 的多个方面(例如 Google 自己的公共和内部 API,以及用户使用Google Cloud Endpoints部署的服务)。
该服务允许用户在其 Google Cloud Platform项目上启用/禁用服务,列出可用服务(如 Maps API、Gmail API、您有权访问的私有 API 等),并通过服务配置管理自己服务的设置。
开发人员很少需要直接使用此服务,主要通过Google Cloud Console或命令行 (用于启用/禁用服务)或通过 Google Cloud Endpoints(用于管理设置)与它进行交互,但它也有一个非常有趣的API。
此 API 不仅可以完成上述及其官方文档中所述的所有操作,而且还具有一些只有使用该 API 的 Google 服务才能访问的隐藏功能。
这些隐藏的功能可以通过多种方式找到,但最简单和最简单的一种方法是在 Google Cloud Platform 项目上启用服务管理 API并打开用于过滤项目产生的流量的组合框:
在最后一张图片中,列出了通过 API 可用的所有方法,包括非 Google 客户端无法访问的隐藏方法(红色框)。当非 Google 客户端尝试访问时,将会出现 404 错误(有趣的是,错误将出现在 JSON 中,而不是常见的 HTML 报错页面)
此外,与 API 中的隐藏方法相同,一些公共方法接受隐藏参数,但查找起来有点棘手。隐藏方法和隐藏参数都使用了 Google 服务的一项功能,称为“可见性”(在外部记录,但仅由 Google 内部使用)。
知道了这一点,我们可以通过查看 Google Cloud Console 在访问时发出的 HTTP 请求很容易访问这些隐藏的东西!
Google Cloud Console 使用多个公共和私有 Google API 来访问有关项目的信息,它使用自己的客户端进行访问,该客户端具有 API 密钥“AIzaSyCI-zsRP85UVOi0DjtiCwWBwQ1djDy741g”。
该客户端常见的请求如下所示:
GET /v1/services?key=AIzaSyCI-zsRP85UVOi0DjtiCwWBwQ1djDy741g HTTP/1.1
Host: servicemanagement.clients6.google.com
Authorization: SAPISIDHASH <SAPISIDHASH> X-Origin: https://console.cloud.google.com
Cookie: <GOOGLE COOKIES>
浅浅解析一下吧:
- “clients6.google.com”:“googleapis.com”的另一种说法。注: cookie 只能到达 google.com 子域。
- "SAPISIDHASH":是“TIMESTAMP_HASH”形式的值。
- SAPISIDHASH 需要“X-Origin”或“Origin”字段,并验证它是否由受信任网站的授权客户端调用。
- cookie:SID、HSID、SSID、APISID 和 SAPISID。故为获得这些,谷歌用户需要登录。
使用 Google Cloud Console 客户端伪造请求非常容易,因为它是谷歌自己的客户端,它可以访问多个 Google API(包括一些私有 Google API)的一些内部功能,包括服务管理 API。
该客户端具有的几个功能之一是从一开始就创建一个 附加配置的服务(普通客户端将忽略“serviceConfig”参数,因为它是隐藏的,并创建一个没有初始配置的服务),像这样的简单请求:
POST /v1/services?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>
{
"serviceName": "<SERVICE NAME>",
"producerProjectId": "<PROJECT>",
"serviceConfig": {
"name": "<SERVICE NAME>",
"producerProjectId": "<PROJECT>",
"configVersion": 3
}
}
漏洞细节
(下述字段请参考上述请求包理解)
通常,“serviceName”和“serviceConfig.name”参数必须在任何指定两者的请求中匹配,但在创建约束过程中没有被检查,当“configVersion”设置为 1、2 或介于2147483648 和 4294967295 之间的值时(后端发生整数溢出),因此任何用户都可以创建真实的名称的服务(例如“the-expanse.appspot.com”),但配置认为它是不同的服务(例如“my-private-secure-api.appspot.com”)。
这是一个非常危险的情况,一些重要的进程使用服务配置中的名称来执行任何操作,除了检查权限时需要使用服务名称本身。
因此,在配置中使用不同的名称,攻击者可能被允许对不同的服务执行重要操作。
可执行的操作:
禁用他人项目的服务:
使用与之前相同的方法,我们可以创建另一个设置来控制项目是否启用了该服务。请注意,您不能在不属于您的项目上启用您的服务,只能禁用它。
例如,如果我的服务“the-expanse.appspot.com”在其配置中带有“cloudresourcemanager.googleapis.com”,我可以发送以下请求并禁用Cloud SDK上的 Cloud Resource Manager API (使用该项目“google.com:cloudsdktool”):
PATCH /v1/services/the-expanse.appspot.com/projectSettings/google.com:cloudsdktool?updateMask=usageSettings&key=AIzaSyCI-zsRP85UVOi0DjtiCwWBwQ1djDy741g HTTP/1.1
<..SAME HEADERS AS BEFORE...>
{
"usageSettings": {
"consumerEnableStatus": "DISABLED"
}
}