Caja是Google的一个能对html和javascript做XSS过滤的工具,2018年3月笔者发现并向谷歌提交了一个Caja的XSS漏洞。到5月份的时候,这个XSS问题已经被修复,不过我发现谷歌某站点用的是没有打补丁的Caja,所以马上看了下能不能XSS,然而并没有成功。
Caja在解析html和JavaScript文件时会过滤掉敏感的js内容,比如iframe标签、object标签以及像document.cookie这种的敏感的js属性。正常情况是在客户端操作和过滤这些html标签,但如果涉及到远程js标签(比如<script src=”xxx”>这种),那这些远程资源会在服务端进行获取、解析和过滤。
我在自己的服务器上上传了一个js文件https://[attacker].com/script.js
,用来检查谷歌某网站在服务端解析js时有没有XSS漏洞,可惜服务器响应是访问不到这个远程js。
测了半天,结论是Caja只能获取到https://www.google.com
和https://www.gstatic.com
这些来自谷歌官方的远程资源,而像https://www.facebook.com
这种第三方的是访问不了的。
谷歌的这个逻辑不太合乎常理,这么做风险会比较大,因为谷歌的业务线很广泛,一般来说一个URL不太好判断是不是谷歌官方的,会比较容易误判。不过也许在某种情况下,能轻而易举地让谷歌认为是一个来自官方的资源……
一般当我发现谷歌的后端内容服务器的话,我都会先测一下SSRF问题,不幸的是我测试了百来次都没有成功找到漏洞。不管怎么说我确定了Caja是在谷歌的内网中做的抓取,否则不会只加载内部资源,而不能获取第三方资源,这应该是个bug,但是不是安全漏洞还得进行进一步的确认。
因为谷歌云服务的存在,在谷歌自家服务器上托管和运行代码就是一件顺理成章的事情了,我创建了一个云App服务实例,上传了之前放在第三方的js文件,然后在谷歌某站点上引用这个远程js,神奇地发现谷歌Caja获取并且解析了这个js!之后我查看了云App上的记录的远程IP,居然是10.x.x.201这样的一个内网地址,看起来胜利就在眼前了。
我用这个内网IP替换了本来谷歌某站点访问外部js资源的URL,等着服务器响应,花了30秒还没加载出来,又想到谷歌的SSRF可不是那么好挖的,在我要放弃的最后一刻,居然加载出来了,而且不是普通的错误响应码,响应内容大概有1M那么大……难怪加载这么久,打开确认了下全都是内网的数据,我惊呆了!
我并没有扫描谷歌的内网,只是发了以下几个请求证明漏洞存在,并立即向谷歌漏洞赏金计划报告了该漏洞,我是在周六提交的,谷歌响应迅速,在48小时内就修复了,期间我还尝试了能不能引起RCE漏洞,然而并没有成功。下图是Borg的架构图:
第一个请求是发给http://10.x.201/
这个地址的,服务器返回的是Borg的管理页面(文章开头的图),Borg是谷歌内部的大规模集群管理系统,经过搜索查证后,我确认直接访问到了内部Borg系统。虽然谷歌在2014年开源了Borg的下一代产品Kubernetes,开源的Kubernetes日益流行,但是在内部生产环境仍然是依赖Borg的,当然这并不是因为Borg的界面设计(开个玩笑)。
第二个请求是发给 http://10.x.x.1/
这个地址的,响应是另外一个Borg的管理页面,第三个请求是发到http://10.x.x.1/getstatus
,响应的Borg管理页面比前两个有更多的细节,有详细的权限和参数信息。这两个Borglet都是一个实体的后端服务器。
硬件方面,这两台服务器都用了Haswell的CPU,主频2.3G赫兹,72核,相当于一组两台或者三台的Xeon E5 v3的CPU,两台服务器的CPU利用率都在77%,有250G的内存,已经使用了70%,硬盘的容量是2T,基本没有使用,大概只用掉了15G的空间,没有固态硬盘,所以数据应该不是存在这两台服务器上的。
机器上的任务非常多,是整合优化过的,有一些任务用消耗的是内存,有的消耗CPU或者网络资源,还有一些任务是高优先级的,有一些视频编码、邮箱和广告的服务比较频繁,这些看起来都是正常的,视频处理起来本来就比较耗资源,Gmail是谷歌的主要服务,广告也是谷歌的核心业务。
我没有找到谷歌站点或者Caja的任务,要不就是走了代理,要不就是Borg的10.x.x.201和我在谷歌云App上收集到的IP是不同的内网。
参考谷歌的架构,我基本上找到了和谷歌Stack的几乎所有的组件相关的任务,特别是 MapReduce, BitTable, Flume, GFS…等等这些。
技术方面,大部分用的语言都是java,没有发现部署过Python、C++、NodeJs或者Go语言,当然结论也不能下的太早了,说不定是我没有发现呢。
Borg和Kubernetes一样,都是依赖Docker和VM这样的容器,但视频处理好像使用的是谷歌的开源工具Gvisor,大概是为了在容器的性能和VM安全之间做的一个平衡吧。
不同参数会展示如何到达端口的应用信息的,在Borg系统里,好像所有的应用都是用的同一个IP地址,用不同的服务端口区分。
应用中的对象是最有意思的,因为这些基本就是源代码了,我发现了一些谷歌没有公开的有趣小算法:
MSCR(M(Customer.AdGroupCriterion+Customer.AdGroupCriterion-marshal+FilterDurianAdGroupCriterion+FilterNeedReviewAdGroupCriterion+GroupAdGroupCriterionByAdGroupKey+JoinAdGroupData/MakeUnionTable:3)+M(JoinAdGroupData/MakeUnionTable:2)+M(Customer.AdGroup+Customer.AdGroup-marshal+FilterDurianAdGroup+ParDo(AdGroupDataStripFieldsFn)+JoinAdGroupData/MakeUnionTable)+R(JoinAdGroupData/GroupUnionTables+JoinAdGroupData/ConstructJoinResults+JoinAdGroupData/ExtractTuples+ExtractCreativeAndKeywordReviewables))
还有Gmail的系统管理用户是gmail@prod.google.com
gmail@prod.google.com
还有一个用户“legal-discovery@prod.google.com”在数据库记录mdb:all-person-users 中有“auth.impersonation.impersonateNormalUser”的权限(澄清一下,只是在一个大数组中看到的信息,按照字面意思理解,不一定准确)。
也有一些历史信息证明有很多的项目在实现之前就被中断了。
/getFile?FileName=/sys/borglet/borglet.INFO
大量的URL是去访问其他的服务器或者终端,我觉得比较有戏的一个http://wiki/
地址也访问不到,详细的路径是
/getFileFileName=/sys/borglet/borglet.INFO
我是在2018年5月12日(周六)提交的漏洞,系统自动判定为P3,大概是个中危的等级,周天我又给谷歌安全团队发了一封邮件,希望有人能跟进下,周一上午风险等级被修改成了P0,也就是严重级别,再后来改为P1高危,周一晚上漏洞修复,有风险的后端就下线了。
要确定SSRF的影响范围不太容易,要看在内网里能访问到多少信息,谷歌一般是在内部使用大量的web站点来维持基础架构,也就是说,一旦发生SSRF,就意味着可以访问到大量的内部web应用,不过好在很多系统都做了鉴权和身份认证,降低了SSRF的危害。
我提的这个漏洞里,正好Borglet系统的管理页面没有做身份认证,所以泄漏了大量的基础信息,或许在继任产品Kubernetes中是做了授权的,所以没有泄漏。
谷歌VRP奖励我$13337,相当于任意文件访问的等级,对方解释说虽然大部分资源都需要权限校验,但很多开发人员在调试程序时都有很大的权限,可能造成的问题不仅仅是信息泄漏,因此按照最高的风险等级来奖励。也感谢谷歌的奖金、负责任的态度和迅速的响应,当然也希望谷歌不会因为我这篇文章追责(开个玩笑,文中所有敏感信息都处理掉了)。
这就是我发现谷歌SSRF的全过程,希望大家能有所收获,欢迎大家踊跃交流。