本Lab学习到关于AngularJS的 xss 漏洞利用
直接输入回显页面,但是把<>进了 html 编码了
当我们输入{{1+1}}
,没有当作字符处理,而是执行了
{{}}
是多种前端框架(如 Vue、Angular、Django 模板等)中常见的模板插值语法,主要用于将数据动态绑定到视图,双花括号 {{1+1}}
包裹的表达式会执行运算。
测试{{alert()}}
,因为存在沙箱机制过滤了危险字符
这里用到新的绕过方法{{ $eval.constructor('alert()')() }}
下面分析为什么这样可以执行alert()
创建 AngularJS 代码
<!DOCTYPE html>
<html>
<head>
<title>AngularJS</title>
<!-- 引入AngularJS库(1.6.9版本) -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
</head>
<!-- 定义Angular应用(模块名为myApp)和控制器(myCtrl)的作用域 -->
<body ng-app="myApp" ng-controller="myCtrl">
<!-- 双向数据绑定:显示$scope.firstName的值 -->
{{ firstName }}
<!-- 表达式计算:直接输出1+1的结果2 -->
{{ 1+1 }}
</body>
<script>
// 创建AngularJS模块(名为myApp),空数组表示无依赖模块
var app = angular.module("myApp", []);
// 定义控制器myCtrl,注入$scope服务
app.controller("myCtrl", function($scope) {
// 在$scope上定义firstName属性,初始值为"John"
$scope.firstName = "John";
});
</script>
</html>
当我们在代码中加入{{ $eval.constructor('alert()')() }}
,通过构造函数执行alert()
创建一个<p id="test"></p>
angular.element(document.getElementById('test')).scope();
获取的作用域对象
$id=2
是子作用域
任何时候我们创建 javascript 对象,都会从原型Prototype继承一些默认属性,例如$eval
和$on
$id=1
是根作用域,来自Prototype
我们可以定义一个函数function test()
,最后通过test()
调用这个函数执行打印输出Hello world!
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/Function
手册中查看关于Function() Constructor
虽然这是创建函数的方式,但不推荐这样做
根据上面的方法重新写一个函数
若不将函数赋给某个变量,将不会执行
记住前面说的
我们直接在后面加()
即可调用函数
所以此时再看本次Lab解题 payload最后这个
()
就是在调用前面通过构造函数创建的函数
这次我们直接看下test()
函数的构造函数,就是Function()
构造函数,因为它可以创建Function
对象
在AngularJS中,$on
是Scope
对象的方法,用于监听事件。作为函数,它本身是Function的实例,因此其constructor
属性指向Function
构造函数
$on.constructor('alert()')
等价于 Function('alert()')
,生成一个匿名函数,再通过 ()
调用该函数,于是就形成了最终的 payload
为什么不能直接{{Function('alert()')()}}
,因为有防护机制,所以要用scope
对象的方法的构造函数传入 payload 执行
PortSwigger 靶场实战持续更新中
echo "Quermeinhumike+8mmh0dHBzOi8vd3d3LmJpbGliaWxpLmNvbS92aWRlby9CVjE4cDdyejhFaDgv
P3ZkX3NvdXJjZT0zMGU4ODFmYzYxYjJkYWFjMDVmYWFkN2RmZjAyMjMxZgo="|base64 -d