原文翻译:https://www.ezequiel.tech/2020/05/rce-in-cloud-dm.html
注:这篇文章曾获得过2020 GCP VRP 一等奖,LiveOverflow制作了一段精彩的视频来阐述漏洞是如何被发现的。
通过使用Google Cloud Deployment Manager的内部(dogfood)版本,攻击者能够通过 Google 的Global Service Load Balancer向某些Google 内部端点发出请求从而来实现RCE操作。
攻击思路为:通过向部署管理器请求创建Type Provider来实现,添加一个名为googleOptions的未记录字段,如下所示:
POST https://www.googleapis.com/deploymentmanager/staging_dogfood/projects/<PROJECT>/global/typeProviders?access_token=<TOKEN> HTTP/1.1
{
"name": "hack",
"descriptorUrl": "https://<GSLB target's path to a descriptor document>",
"googleOptions": {
"gslbTarget": <GSLB target name>,
"descriptorUrlServerSpec": <GSLB target name>,
"ownershipKind": "GOOGLE",
"credentialType": "GAIAMINT",
"transport": "GSLB"
}
}
如果你还是没明白,建议看看下面的基础知识和漏洞细节!
相关知识
Deployment Manager是一项 Google Cloud 服务,它提供了一种以编程方式(基础架构即代码)处理基础架构资源的创建、删除和修改的方法。
相关Deployment Manager概念:
Tip:
起初有点难以理解Google Cloud Deployment Manager,如果您对它感兴趣,建议手动尝试一下,可以阅读相关文档,并尝试创建部署和类型提供程序来掌握它。
漏洞挖掘过程
小插曲
我研究了Deployment Manager API方法,在 Google Cloud Console上启用它,转到指标页面,然后查看部分Filters,,其中有一个名为Methods的下拉列表,其中包含所有这些方法(包含禁用方法),--在这些方法中通常会泄露API版本信息
我注意到除了v2和v2beta (记录的版本)之外还有两个 API 版本,称为alpha和dogfood。我可以在这些版本上调用方法,只需在每个 API 调用中用alpha或dogfood替换v2或v2beta 。
dogfood版本更有趣,特别是因为我注意到dogfood这个词被用于谷歌服务中内部测试。(也许这个版本有内部功能,只适用于谷歌!)
当我列出该版本的基本类型时,它们中的大多数都在其定义中返回了一个额外的字段:googleOptions。请仔细查看对比图:
上图分析:
当我列出我自己的Type Providers时,他们还包含了这个额外的字段,并在我的查询中指定了$outputDefaults 系统参数,我可以看到googleOptions字段里面有哪些字段。
injectProject
布尔值。无论我指定什么值,部署管理器 API总是在我的Type Providers上将其设置为false。
deleteIntent
我能够找到一个有效值:CREATE_OR_ACQUIRE
isLocalProvider
布尔值。每当我将其设置为true时,无论任何其他字段中的值如何,都会成功创建Type Provider
ownershipKind
有效值为UNKNOWN、USER和GOOGLE。将其设置为这些值中的任何一个都没有观察到任何影响,但我在研究期间总是将其设置为GOOGLE。
transport
我最初找到的有效值是:UNKNOWN_TRANSPORT_TYPE和HARPOON。将其设置为这些值中的任何一个都不会产生任何影响。
credentialType
我最初找到的有效值是: UNKNOWN_CREDENTIAL_TYPE和OAUTH。将其设置为这些值中的任何一个都无影响。
gslbTarget
字符串。要么是空的,要么是类似 blade:<TARGET>或gslb: <TARGET>。无影响
descriptorUrlServerSpec
String,与gslbTarget相同或为空。无影响
GSLB是 Google 的全球服务负载均衡器,它的作用类似于内部 DNS 服务器和负载均衡器之间的混合。
根据 SRE Book,当GSLB被提供一个符号名称(有点像域名)时,它将把流量引导到一个链接的BNS 地址( Borg Naming Service),这是一个内部 IP 地址的 Google 等价物。故可以肯定存在SSRF。但是无论我在gslbTarget和descriptorUrlServerSpec上尝试了什么值,它们似乎都没有任何效果。
突破:在 HTTP 上利用 Proto
在几次尝试取得重大成果都失败后,终于在一次突发奇想中成功拨云见月!
有一天,我想到了使用协议缓冲区(Google 开发的一种二进制序列化格式)来找出credentialType和传输 Enums的缺失值,因为在 protobuf 中,Enums表示为 numbers,而不是Strings,所以我可以从 1 开始计数,直到我停止寻找新值。
我调用了API 的get Type Provider方法,并使用名为protoc(Protocol Buffers 编译器)的工具及其--decode_raw 选项解码了响应 protobuf 。
比较检索到的 proto 中的值和 JSON API 中的值,我快速将每个字段编号与其字段名称匹配,并对Type Providers proto 消息定义进行逆向。
上述过程的示例如下:
我通过 JSON API 创建了一个Type Provider:
我通过 JSON API 获得了相同的Type Provider:
我通过 Proto over HTTP API 获得了相同的Type Provider:
我用 protoc 解码响应包:
我找出每个字段对应的数字(例如,1=name,2=id,3=insertTime,...)
我用该信息构造了原始原始消息定义的近似值
至此,我便可以得到缺少的关键值:
- transport
- GSLB - It directs requests from the Deployment Manager to the internal Google endpoints specified in gslbTarget and descriptorUrlServerSpec
- credentialType
- ENDUSERCREDS, TYPE_CREDENTIAL - They seem to act the same way as OAUTH and UNKNOWN_CREDENTIAL_TYPE
将传输设置为GSLB是发出内部请求的关键!
使用新发现的GSLB的请求值,我可以构造 Type Providers以便 Deployment Manager将请求直接定向到内部 Google 端点。
经过测试,这个Type Provider非常完美,我成功创建了一个Deployment(部署),可以使用它在GAE 测试中启动一个新应用程序。
赏金
我将漏洞提交后,谷歌将其视为RCE,并发放了 $31,337 的奖励,非常感谢 Google VRP!