在本节中,将描述Angular JS沙箱,解释漏洞如何从沙箱中逃脱,并说明如何在Angular JS沙箱的环境中绕过内容安全策略(CSP)。
什么是Angular JS沙箱?
Angular JS沙箱是Angular JS的一种机制,可防止在Angular JS模板表达式中访问潜在危险对象,例如窗口或文档。它还可以防止访问具有潜在危险的属性,例如_proto_。
尽管Angular JS团队没有将其视为安全边界,但开发人员通常并不这么认为。
虽然绕过沙箱最初很困难,但安全研究人员已经发现了许多这样做的方法。结果,沙箱最终在1.6版本中从Angular JS被删除。然而,许多遗留应用程序仍然使用旧版本的Angular JS,因此可能容易受到攻击。
Angular JS沙箱是如何工作的?
沙箱的工作原理是解析表达式,重写JavaScript,然后使用各种函数测试重写的代码是否包含任何危险对象。
例如,ensureSafeObject()函数检查给定对象是否应用自身,这是检测窗口对象的一种方法。通过检查构造函数属性是否引用自身,以大致相同的方法检测Function构造函数。
ensureSafeMemberName()函数检查对象的每个属性访问,如果它包含_proto_或_lookupGetter_等危险属性时,则该对象将被阻止。
ensureSafeFunction()函数可以防止调用call()、apply()、bind()或constructor()。
Angular JS沙盒逃逸是如何工作的?
沙箱逃逸涉及诱使沙箱认为恶意表达是良性的,最著名的转义是在表达式中全局使用修改后的charAt()函数:
攻击通过使用[].join方法覆盖函数来进行,这会导致charAt()函数返回发送给它的所有字符,而不是特定的单个字符。由于Angular JS中isldent()函数的逻辑,它会将它认为的单个字符与多个字符进行比较。由于单个字符总是小于多个字符,isldent()函数总是返回true,如下所示:
一旦isldent()函数被欺骗,就可以注入恶意JavaScript。
例如,像$eval('x=alert(1)')这样的表达式是被允许的,因为Angular JS将每个字符都视为一个标识符。但要注意,需要使用Angular JS的$eval()函数,因为覆盖charAt()函数只有在沙盒代码执行后才会生效。然后,这个技术将绕过沙箱并允许任意JavaScript执行。
构建一个高级Angular JS沙箱逃逸
我们已经了解了基本沙盒转义的工作原理,但可能会遇到对允许使用的字符有更多限制的网站。
例如,网站可能会阻止使用双引号或单引号。在这种情况下,需要使用注入String.fromCharCode()之类的函数来生成字符。
尽管Angular JS阻止在表达式中访问String构造函数,但是可以通过使用字符串的构造函数属性来解决这个问题。这显然需要一个字符串,因此要构造这样的攻击,需要找到一种不使用单引号或双引号来创建字符串的方法。
在标准沙盒逃逸中,将使用$eval()来执行JavaScript的Payload,但在下面的试验中,$eval()函数是未定义的。幸运的是,我们可以使用orderBy过滤器,过滤器典型的语法如下:
注意,|运算符的含义与JavaScript中的不同。通常,这是一个按位OR操作,但在Angular JS中它表示过滤操作。在上面的代码中,我们将左侧的数组[123]发送到右侧的orderBy过滤器,冒号表示要发送到过滤器的参数,在本例中是一个字符串。orderBy过滤器通常用于对对象进行排序,但它也接受表达式,这意味着我们可以使用它来传递Payload。
可以通过后面这个试验进一步理解Angular JS沙箱的逃逸。
场景试验-在Angular JS沙箱逃逸无字符串进行反射型XSS攻击:
https://portswigger.net/web-security/cross-site-scripting/contexts/angularjs-sandbox/lab-angular-sandbox-escape-without-strings
场景说明:
这个试验场景以一种不寻常的方式使用Angular JS,其中$eval函数不可用,无法在Angular JS中使用任何字符串。
试验目的:
要完成这个试验,需要执行跨站脚本攻击,以逃避沙箱并执行alert()函数,而无需使用$eval()函数。
攻击过程:
①直接在浏览器中输入如下URL即可完成试验,注意替换下试验场景地址
https://your-lab-id.web-security-academy.net/?search=1&toString().constructor.prototype.charAt%3d[].join;[1]|orderBy:toString().constructor.fromCharCode(120,61,97,108,101,114,116,40,49,41)=1
试验小结:
这个漏洞利用toString()不使用引号创建字符串,随后获取字符串原型并覆盖每个字符串的charAt函数,这就对Angular JS沙箱进行了破坏。接下来,将一个数组传递给orderBy过滤器后,再次使用toString()函数创建一个字符串和String构造函数属性,为过滤器设置参数。最后,使用fromCharCode方法通过将字符代码转换为字符串x=alert(1)(也就是那一串数组)来生成Payload。
Angular JS CSP绕过是如何工作的?
内容安全策略(CSP)绕过的工作方式与与标准沙箱转义类似,但通常涉及一些HTML注入。当CSP模式在Angular JS中处于活动状态时,它会以不同的方式解析模板表达式并避免使用Function构造函数。这意味着上述标准沙箱逃逸将不起作用。
根据具体策略,CSP将阻止JavaScript事件。然后,Angular JS定义了它自己的事件来替代使用。在内部,Angular JS定义了一个特殊的$event对象,它简单地引用浏览器事件对象,可以使用此对象执行CSP绕过。
在Chrome上,$event对象上有一个特殊的属性,称为path。这个属性包含导致事件执行的对象数组。最后一个属性始终是window对象,我们可以使用它来执行沙盒逃逸。通过将数组传递给orderBy过滤器,我们可以枚举该数组并使用最后一个元素(窗口对象)来执行一个全局函数,例如alert()。下面这段代码是一个演示:
注意,使用from()函数,它允许将对象转换为数组并在该数组的每个元素上调用给定函数(在第二个参数中指定)。在这种秦光霞,我们就可以调用alert()函数了。使用from()函数可以有效地从沙箱中隐藏窗口对象,从而允许注入恶意代码。
使用Angular JS沙箱转义绕过CSP
下面这个试验采用了长度限制,需要想办法从Angular JS沙箱中隐藏窗口对象。
一种方法是使用array.map()函数,如下所示:
map()接受一个函数作为参数,并将为数组中的每个项目调用它。这将绕过沙箱,因为在没有明确引用窗口的情况下使用了对alert()函数的引用。
场景试验-在Angular JS沙箱中逃逸CSP进行反射型XSS攻击:
https://portswigger.net/web-security/cross-site-scripting/contexts/angularjs-sandbox/lab-angular-sandbox-escape-and-csp
场景说明:
这个试验场景使用了CSP和Angular JS。
试验目的:
要完成这个试验,需要绕过CSP、逃避Angular JS沙箱并执行alert(document.cookie)的跨站脚本攻击。
攻击过程:
①打开"exploit server",并将下面Payload输入到"Body"中,注意替换下试验地址
<script>
location='https://your-lab-id.web-security-academy.net/?search=<input id=x ng-focus=$event.path|orderBy:'(z=alert)(document.cookie)'>#x';
</script>
②保存后发送给受害者,即可完成试验。
试验小结:
这个漏洞利用Angular JS中的ng-focus事件来创建绕过CSP的事件。还使用了$event,这是一个引用事件对象的Angular JS变量。Path属性特定于Chrome浏览器,包含触发事件的元素数组,这个数组中的最后一个元素包含窗口对象。
在orderBy过滤器的参数中,并没有直接调用alert()函数,而是将其分配给变量z。只有当oederBy操作到达$event.path数组中的窗口对象时,才会调用该函数。这意味着它可以在窗口范围内调用,而无需显式引用窗口对象,这样就有效地绕过了Angular JS的窗口检查。
SQL注入攻击-检索隐藏的数据
HTTP Host头漏洞攻击-概念梳理
原文始发于微信公众号(H君网安白话):跨站脚本攻击XSS-Angular JS 沙箱
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论