https://nechudav.blogspot.com/2020/11/31k-ssrf-in-google-cloud-monitoring.html
Google Cloud中的每个虚拟机都在元数据服务器上存储其元数据。这些元数据包括项目ID、服务账户信息、虚拟机的信息或公共ssh密钥。元数据可能从实例内部(从IP地址169.254.169.254)或来自计算引擎API。
Google Cloud监控提供的服务之一是正常运行时间检查。正常运行时间检查是一项服务,它定期向一个资源发送请求,看它是否有反应。检查可以用来确定应用引擎、虚拟机实例、URL等的可用性。
我开始通过创建一个正常运行时间检查功能来测试SSRF的这个功能,它向一个URL/IP地址发送请求。大多数的URL和IP地址,也就是通常的SSRF目标都被阻止了。但是,由于云监控本身是在Google Cloud虚拟机实例上运行的,我有可能尝试请求元数据API,因为对元数据API本身的请求将从实例中发出。
值得注意的是,当从虚拟机内部查询元数据时,需要包括头 "Metadata-Flavor: Google"(旧版本的元数据API不需要这个标头)。有一个选项可以在请求中添加自定义头信息。
我用以下参数创建了正常运行时间检查。
Protocol: HTTP
Hostname: 169.254.169.254
Path: /computeMetadata/v1/project/project-id
Custom Headers: Metadata-Flavor: Google (required for /v1/ metadata endpoints)
然后我按下了正常运行时间检查创建表格底部的测试按钮,它向元数据服务器发送了一个请求,然后显示检查成功了。
我看到的响应是。
因为响应代码是200,响应时间是2毫秒,我确信通过正常运行时间检查,元数据API是可以到达的(请求外部URL会花费更多时间)。问题是,无法看到响应的内容。只有两样东西被返回,那就是响应代码和响应时间。所以这里是一个盲SSR
例如,我将尝试响应是否包含字符'a'、'b'、'c'...... 比方说,我发现响应中包含'c'。然后我将继续尝试预置或附加另一个字符,并试图找到响应是否包含字符'ca'、'cb'、'cc'...... 然后,如果我发现响应中返回了'ca',我将尝试其他组合--'caa'、'cab'、'cac'......并重复这一过程,直到我得到响应。
为了进行响应体的验证,按下正常运行时间检查表中的测试按钮时,即可调用该API
这个请求看起来像这样。
通过这个脚本,我获得了项目级元数据--公共SSH密钥、项目名称和其他关于谷歌云监控项目的信息。也可以得到实例级的元数据,这些元数据对所有实例都是一样的(机器类型、CPU平台......)。但我在获取实例级元数据时遇到了困难,这些元数据对每个实例或定期刷新的数据都是唯一的(例如服务账户令牌、实例的IP地址)。这是因为正常运行时间检查服务是在世界各地的多个实例上运行的(大约有54个运行的实例),对服务的请求是负载平衡的。所以不能保证多个请求会被发送到同一个实例上。获得独特的实例级元数据将需要发送大量的请求,这是有问题的,因为API是有速率限制的,这将是非常耗时的。在这一点上,我没有继续进行研究。
我报告了这个问题,它被接受了,谷歌VRP为这个错误奖励了我31337美元。我想感谢谷歌VRP团队的奖励和快速反应。
报告的时间。2020年6月
更新:谷歌工程师找到了一个非常好的、聪明的方法,通过使用二进制搜索和regex减少请求的数量来获得访问令牌。下面是描述他们解决方案的评论。
评论:实际上,在与同样的限制作斗争后,我们最终写了一个漏洞来获取访问令牌。两个主要的技巧是对每个字符进行二进制搜索(发送更少的请求)和探测正负匹配(获得可靠的结果)。比如说。
- foo[a-n]
- foo[^a-n]
当我们碰到正确的API时,这些请求中最终肯定会有一个成功的响应返回。我们会重复查询(达到一定的限度),直到我们得到任何成功的响应,然后在此基础上调整搜索空间。由于有了regexps,你可以并行地探测多个字符(foo[a-n], foo. [a-n], foo...[a-n])。在开始时令牌会重叠,但在~10个字符左右后,我们通常有一个独特的前缀。访问令牌的有效期为60分钟,所以平均来说你有30分钟。最后,这个漏洞花了~15分钟来获得一个完整的访问令牌,包括速率限制。有趣的错误。:)
原文始发于微信公众号(火线Zone):价值3w美元的Google Cloud SSRF
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论