Mail.qq.com DOM XSS
First, we found a getcontent
http://mail.qq.com/cgi-bin/readtemplate?t=compose✓=false&getcontenturl=http://mail.qq.com/test
View called Functions
if(c&&/^https?:\/\/([\w]+\.)?mail\.qq\.com(\/)/i.test(c)){b.loadJsFile(c,false,b.document,function(){if(!b.goAsyncContent||!b.goAsyncContent.content){b.goAsyncContent={};b.showError("\u90AE\u4EF6\u5185\u5BB9\u83B7\u53D6\u5931\u8D25");}});...
Here, the regular expression determines https://xxx.mail.qq.com/xxx. if trueis returned, loadjsfile (URL)
View loadJsFile ()
function loadJsFile(e, a, d, b, c, f) { var n = getTop(), j = d || document, h = typeof b == "function", l, m, k = n.loadJsFile, o = n.getRes(e), i = k._oDatas || (k._oDatas = {}); if (QMDistributeDomain.isRelativeUrl(o)) { o = QMDistributeDomain.addHost(o); } if (typeof(f) == 'boolean') { f = { bAutoRemove: f }; } else if (!f) { f = {}; } if (a) { m = k.getLoadedScript(o, j); if (m) { if (h) { var p = m.getAttribute("_key_"); if (i[p] === true) { callBack.call(m, b); } else { i[p].push(b); } } return m; } } m = j.createElement("script"); if (!c) { c = {}; } if (typeof(c.crossOrigin) != 'string') { if (c.crossOrigin !== false && k.checkCrossOrigin(o)) { c.crossOrigin = '*'; } else { delete c.crossOrigin; } } if (f.bReload) { o += (o.indexOf('?') != -1 ? '&': '?') + 'r=' + Math.random(); } n.E(c, function(r, q) { m.setAttribute(q, r); }); var p = n.unikey(); m.setAttribute("_key_", p); i[p] = []; function g() { var q = this, r = q.getAttribute("_key_"); callBack.call(q, b); n.E(i[r], function(s) { s(); }); i[r] = true; if (f.bAutoRemove) { n.removeSelf(m); } q.onreadystatechange = q.onload = q.onerror = null; } (GelTags("head", j)[0] || j.documentElement).appendChild(extend(m, { onerror: function() { if (c.crossOrigin) { debug('crossOrigin error file:' + o); n.ossLogCustom('delay', 'all', 'corsError', e); n.LogKV({ sValue: 'getinvestigate|jsload|cors|jserr' }); c.crossOrigin = false; f.bReload = true; n.removeSelf(m); m.onreadystatechange = m.onload = m.onerror = null; k(e, false, d, b, c, f); } else { debug('file load error:' + o); } }, onload: g, onreadystatechange: function() { var q = this; ({ loaded: true, complete: true } [q.readyState]) && g.call(this); } }, { type: "text/javascript", charset: c.charset || "gb2312", src: c.crossOrigin ? (o.indexOf('?') > 0 ? o + '&r=o': o + '?r=o') : o })); return m;}
Is a function for dynamically loading JS. However, in combination with the above, only files under * .mail.qq.com/can be loaded
Bypass: jsonpToJs
Jsonp callback can be customized. Therefore, jsonp can be constructed into any JS statement.
Jsonp under * .mail.qq.com/can modify callback to make the content look like this
alert()//([{title : "cgi exception"...);
As the content below is commented, alert () can be successfully constructed to load external domain JS. Although, looking for such a jsonp is like a haystack.
This vulnerability status is ignored. Thanks for submitting repair suggestions, but it is actually required by the business.
However, the author believes that this vulnerability can be completely fixed by detecting the value of the incoming getcontenturl, removing the jsonp that does not comply with the business specifications, or improving the regular expression detection, it is inappropriate to ignore this vulnerability.
Jsonp involved in the vulnerability is not disclosed because the vulnerability is not fixed.