mail.qq.com DOM XSS
首先发现一处getcontent
http://mail.qq.com/cgi-bin/readtemplate?t=compose✓=false&getcontenturl=http://mail.qq.com/test
查看调用的函数
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"); } });...此处正则判断了 https://xxx.mail.qq.com/xxx如果正则返回true,则loadJsFile(URL)
查看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; }是动态加载JS的函数。但是结合前面,只能加载 *.mail.qq.com/下的文件
绕过: jsonpToJs
由于jsonp的callback 通常可以自定义,因此通常可以构造成任意JS语句
存在 *.mail.qq.com/ 下的jsonp 可以通过修改callback使得内容看起来是这样
alert()//([{title : "cgi exception"...);由于//注释了后面的内容,因此成功alert(),进而可以构造出加载外部域JS,虽然,寻找这样一个jsonp犹如大海捞针。
