Bug Bounty:通过Google Voice扩展程序在accounts.google.com上触发基于DOM的XSS。
2020-06-23 10:33:56 Author: xz.aliyun.com(查看原文) 阅读量:273 收藏

这个基于DOM的XSS是偶然间发现的,这一切都归功于Google Ads的customer ID和美国的电话号码格式相同。当我打开Gmail并查看我的收件箱时,弹出如下内容


Gmail中存储型XSS是由Google ads规则触发的,为了避免上当受骗,我立即向google报告了这个事。

触发有两个条件
1:安装了Google语音扩展程序
2:收件箱中有下列文本消息:'444-555-4455 <img src=x onerror=alert(1)>'
Google语音扩展程序可以在accounts.google.comfacebook.com.上执行任何javascript。


我查看了Google语音扩展程序的源代码,发现在文件contentscript.js中,有一个名为Wg()的函数,正是这个函数触发了XSS。

function Wg(a) {
    for (var b = /(^|\s)((\+1\d{10})|((\+1[ \.])?\(?\d{3}\)?[ \-\.\/]{1,3}\d{3}[ \-\.]{1,2}\d{4}))(\s|$)/m, c = document.evaluate('.//text()[normalize-space(.) != ""]', a, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null), d = 0; d < c.snapshotLength; d++) {
        a = c.snapshotItem(d);
        var f = b.exec(a.textContent);
        if (f && f.length) {
            f = f[2];
            var g = "gc-number-" + Ug,
                h = '<span id="' + g + '" class="gc-cs-link"title="Call with Google Voice">' + f + "</span>",
                k;
            if (k = a.parentNode && !(a.parentNode.nodeName in Og)) k = a.parentNode.className,
                k = "string" === typeof k && k.match(/\S+/g) || [], k = !Fa(k, "gc-cs-link");
            if (k) try {
                if (!document.evaluate('ancestor-or-self::*[@googlevoice = "nolinks"]', a, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null)
                    .snapshotLength) {
                    if (0 == a.parentNode.childElementCount) {
                        var w = a.parentNode.innerHTML,
                            y = w.replace(f, h);
                        a.parentNode.innerHTML = y
                    } else {
                        w = a.data;
                        y = w.replace(f, h);
                        var u = Qc("SPAN");
                        u.innerHTML = y;
                        h = u;
                        k = a;
                        v(null != h && null != k, "goog.dom.insertSiblingAfter expects non-null arguments");
                        k.parentNode && k.parentNode.insertBefore(h,
                            k.nextSibling);
                        Vc(a)
                    }
                    var t = Ic(document, g);
                    t && (Ug++, nc(t, "click", ma(Sg, t, f)))
                }
            } catch (E) {}
        }
    }
}

这个函数原理并不难,开发人员在body元素内容中查找电话号码,然后使用获取的电话号码作为其内容创建另一个span元素,这样方便用户直接在网页上直接单击拨打该电话。
从第1行到第9行,它使用document.evaluate循环遍历body元素的内容,document.evaluate可以在HTML和XML文档中进行搜索,返回表示结果的XPathResult对象,在这里它用于测定和获取所有Body元素的内容,并选择当前节点中的所有文本节点并将其赋给变量‘a’,这里就存在一个DOM-Xpath注入:

(var b = /(^|\s)((\+1\d{10})|((\+1[ \.])?\(?\d{3}\)?[ \-\.\/]{1,3}\d{3}[ \-\.]{1,2}\d{4}))(\s|$)/m, c = document.evaluate('.//text()[normalize-space(.) != ""]', a, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null), d = 0; d < c.snapshotLength; d++) {
        a = c.snapshotItem(d);

然后与存储在变量‘a’中的返回结果中执行匹配搜索。(变量‘b’是美国电话号码格式的正则表达式)如果找到匹配项,则将其赋给变量‘f’,然后将其作为span元素的内容放入变量‘h’中。
第10行和第11行检查标签名称,由于变量'f'的内容来自HTML元素,既不是这些标签Script、Style、Head、Object、TEXTAREA、INPUT、SELECT和A中的一个,也不具有“gc-cs-link”的类属性,
这个检查有两个作用:
1)防止扩展与DOM混淆。避免处理SCRIPT, STYLE,HEAD, INPUT, SELECT等标签的内容
2)它会阻止脚本无限循环,因为如果SPAN元素已经存在,就不会继续创建。

第12行到27行,有一个if条件,如果变量k为TRUE,则表示没有找到类属性名为“gc-cs-link”的元素,然后执行try,try语句内还存在另一个if条件检查,如果找不到具有“googlevoice”属性和“nolinks”值的元素,则再次执行document.valuate,然后嵌套IF条件检查变量‘a’是否没有子元素,如果没有,执行下列语句

w = a.parentNode.innerHTML,
y = w.replace(f, h);
a.parentNode.innerHTML = y

如果a有子元素,则执行下列语句

k.parentNode && k.parentNode.insertBefore(h, k.nextSibling);

Bug原因:在接收器上执行变量‘a’,该变量保存有效负载: '444-555-4455 <img src=x onerror=alert(1)>'

修复步骤:
在接收器((innerHTML, insertBefore))上执行保存电话号码值(例如+12223334455)的变量‘f’

$3,133.7

原文:http://www.missoumsai.com/google-accounts-xss.html

文章来源: http://xz.aliyun.com/t/7898
如有侵权请联系:admin#unsafe.sh