这个基于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.com
和facebook.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