原型链污染例题

首先介绍一下原型链

JS中prototype__proto__分别是什么?

我们可以认为原型prototype是类Foo的一个属性,而所有用Foo类实例化的对象,都将拥有这个属性中的所有内容,包括变量和方法。
我们可以通过Foo.prototype来访问Foo类的原型,但Foo实例化出来的对象,是不能通过prototype访问原型的。这时候,就该__proto__登场了。

一个Foo类实例化出来的foo对象,可以通过foo.__proto__属性来访问Foo类的原型,也就是说:

foo.__proto__ == Foo.prototype

总结一下:

  1. prototype是一个类的属性,所有类对象在实例化的时候将会拥有prototype中的属性和方法
  2. 一个对象的__proto__属性,指向这个对象所在的类的prototype属性

JavaScript原型链继承

所有类对象在实例化的时候将会拥有prototype中的属性和方法,这个特性被用来实现JavaScript中的继承机制。

比如:

function Father() {
    this.first_name = 'Donald'
    this.last_name = 'Trump'
}

function Son() {
    this.first_name = 'Melania'
}

Son.prototype = new Father()

let son = new Son()
console.log(`Name: ${son.first_name} ${son.last_name}`)

Son类继承了Father类的last_name属性,最后输出的是Name: Melania Trump

总结一下,对于对象son,在调用son.last_name的时候,实际上JavaScript引擎会进行如下操作:

  1. 在对象son中寻找last_name
  2. 如果找不到,则在son.__proto__中寻找last_name
  3. 如果仍然找不到,则继续在son.__proto__.__proto__中寻找last_name
  4. 依次寻找,直到找到null结束。比如,Object.prototype__proto__就是null

哪些情况下可以用原型链污染

在实际应用中,哪些情况下可能存在原型链能被攻击者修改的情况呢?

我们思考一下,哪些情况下我们可以设置__proto__的值呢?其实找找能够控制数组(对象)的“键名”的操作即可:

  • 对象merge 结合 拼接
  • 对象clone(其实内核就是将待操作的对象merge到一个空对象中) 复制

以对象merge为例,我们想象一个简单的merge函数:

function merge(target, source) {
    for (let key in source) {
        if (key in source && key in target) {
            merge(target[key], source[key])
        } else {
            target[key] = source[key]
        }
    }
}

在合并的过程中,存在赋值的操作target[key] = source[key],那么,这个key如果是__proto__,就可以原型链污染
我们用如下代码实验一下:

let o1 = {}
let o2 = {a: 1, "__proto__": {b: 2}}
merge(o1, o2)
console.log(o1.a, o1.b)

o3 = {}
console.log(o3.b)

结果是,合并虽然成功了,但原型链没有被污染:
在这里插入图片描述
这是因为,我们用JavaScript创建o2的过程(let o2 = {a: 1, "__proto__": {b: 2}})中,__proto__已经代表o2的原型了,此时遍历o2的所有键名,你拿到的是[a, b]__proto__并不是一个key,自然也不会修改Object的原型。

那么,如何让__proto__被认为是一个键名呢?

我们将代码改成如下:

let o1 = {}
let o2 = JSON.parse('{"a": 1, "__proto__": {"b": 2}}')
merge(o1, o2)
console.log(o1.a, o1.b)

o3 = {}
console.log(o3.b)

可见,新建的o3对象,也存在b属性,说明Object已经被污染
这是因为,JSON解析的情况下,__proto__会被认为是一个真正的“键名”,而不代表“原型”,所以在遍历o2的时候会存在这个键。

merge操作是最常见可能控制键名的操作,也最能被原型链攻击,很多常见的库都存在这个问题。

例题

const express = require('express')
var hbs = require('hbs');
var bodyParser = require('body-parser');
const md5 = require('md5');
var morganBody = require('morgan-body');
const app = express();
var user = []; //empty for now

var matrix = [];
for (var i = 0; i < 3; i++){
    matrix[i] = [null , null, null];
}

function draw(mat) {
    var count = 0;
    for (var i = 0; i < 3; i++){
        for (var j = 0; j < 3; j++){
            if (matrix[i][j] !== null){
                count += 1;
            }
        }
    }
    return count === 9;
}

app.use(express.static('public'));
app.use(bodyParser.json());
app.set('view engine', 'html');
morganBody(app);
app.engine('html', require('hbs').__express);

app.get('/', (req, res) => {

    for (var i = 0; i < 3; i++){
        matrix[i] = [null , null, null];

    }
    res.render('index');
})


app.get('/admin', (req, res) => { 
    /*this is under development I guess ??*/
    console.log(user.admintoken);
    if(user.admintoken && req.query.querytoken && md5(user.admintoken) === req.query.querytoken){
        res.send('Hey admin your flag is <b>flag{prototype_pollution_is_very_dangerous}</b>');
    } 
    else {
        res.status(403).send('Forbidden');
    }    
}
)


app.post('/api', (req, res) => {
    var client = req.body;
    var winner = null;

    if (client.row > 3 || client.col > 3){
        client.row %= 3;
        client.col %= 3;
    }
    matrix[client.row][client.col] = client.data;
    for(var i = 0; i < 3; i++){
        if (matrix[i][0] === matrix[i][1] && matrix[i][1] === matrix[i][2] ){
            if (matrix[i][0] === 'X') {
                winner = 1;
            }
            else if(matrix[i][0] === 'O') {
                winner = 2;
            }
        }
        if (matrix[0][i] === matrix[1][i] && matrix[1][i] === matrix[2][i]){
            if (matrix[0][i] === 'X') {
                winner = 1;
            }
            else if(matrix[0][i] === 'O') {
                winner = 2;
            }
        }
    }

    if (matrix[0][0] === matrix[1][1] && matrix[1][1] === matrix[2][2] && matrix[0][0] === 'X'){
        winner = 1;
    }
    if (matrix[0][0] === matrix[1][1] && matrix[1][1] === matrix[2][2] && matrix[0][0] === 'O'){
        winner = 2;
    } 

    if (matrix[0][2] === matrix[1][1] && matrix[1][1] === matrix[2][0] && matrix[2][0] === 'X'){
        winner = 1;
    }
    if (matrix[0][2] === matrix[1][1] && matrix[1][1] === matrix[2][0] && matrix[2][0] === 'O'){
        winner = 2;
    }

    if (draw(matrix) && winner === null){
        res.send(JSON.stringify({winner: 0}))
    }
    else if (winner !== null) {
        res.send(JSON.stringify({winner: winner}))
    }
    else {
        res.send(JSON.stringify({winner: -1}))
    }

})
app.listen(3000, () => {
    console.log('app listening on port 3000!')
})

首先分析一下代码
获取flag的条件是 传入的querytoken要和user数组本身的admintoken的MD5值相等,且二者都要存在。

由代码可知,全文没有对user.admintokn 进行赋值,所以理论上这个值时不存在的,但是下面有一句赋值语句:

matrix[client.row][client.col] = client.data

data,row,col,都是我们post传入的值,都是可控的,所以可以构造原型链污染。

因此可以定义两个变量,
一个变量用于传入data,row,col,使原本没有的admintoken通过原型链污染来使admintoken存在
另一个变量用于get传入url中使admintoken与md5值匹配
在传值的时候注意用json,否则__proto__不会被识别成对象而是一个字符

在这里插入图片描述
这样就用原型链污染成功夺旗

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 尺寸链计算是一种计算尺寸关系的方法,用于确定不同尺寸之间的比例关系。在设计和绘图中,尺寸链计算有着重要的应用。 例如,现在我们需要绘制一幅图,其中一个物体的尺寸已知,而其他物体的尺寸需要按照比例来确定。这时,我们可以使用尺寸链计算来帮助我们确定这些物体的尺寸。 首先,我们需要确定一个尺寸作为基准,可以选择任意一个已知的尺寸作为基准。然后,我们选取另一个物体的尺寸,并与基准尺寸进行比例计算。比如,如果基准尺寸为10cm,而另一个物体的比例为1:2,那么我们可以通过计算得知该物体的尺寸为20cm。 接下来,如果我们需要确定更多物体的尺寸,我们可以按照同样的方法进行计算。比如,如果我们需要确定第三个物体的尺寸,而它与上一个物体的比例为1:3,我们可以得知第三个物体的尺寸为60cm。 通过尺寸链计算,我们可以轻松地确定不同物体之间的尺寸比例关系,从而有效地绘制图形和设计物体。 在实际应用中,尺寸链计算也会遇到一些复杂的情况,比如多个物体之间相互影响的尺寸关系。在这种情况下,我们需要将问题进行细分,逐个计算每个物体的尺寸,并根据其相对关系进行调整。 总之,尺寸链计算是一种重要的计算方法,能够帮助我们确定不同物体之间的尺寸比例关系,从而更好地进行设计和绘图。 ### 回答2: 尺寸链计算是一种计算机图形学中常用的方法,用于确定对象在不同坐标系下的位置和尺寸。它通过定义对象之间的关系,使得一个对象的尺寸和位置可以相对于另一个对象的尺寸和位置进行计算。 尺寸链计算的基本原理是使用一个参考对象,以及它与其他对象之间的关系来计算其他对象的尺寸和位置。参考对象可以是屏幕、窗口、容器等,而其他对象可以是其中的子对象或者其他相关对象。通过维护对象与参考对象之间的关系,可以方便地调整对象的尺寸和位置。 例如,在一个屏幕上有一个方形容器A,容器A中有一个矩形图像B。容器A的位置和尺寸相对于屏幕来说是已知的,而图像B的位置和尺寸相对于容器A来说是已知的。现在需要计算图像B在屏幕上的位置和尺寸,可以使用尺寸链计算。首先,容器A的位置和尺寸可以作为参考,这样图像B的位置和尺寸就可以相对于容器A来计算。然后,通过将容器A的位置和尺寸与图像B的位置和尺寸相加,就可以得到图像B在屏幕上的位置和尺寸。 尺寸链计算在计算机图形学中有广泛的应用,例如在游戏开发中用于物体的布局和碰撞检测,以及在GUI界面设计中用于控件的排列和大小调整等。它提供了一种灵活、简洁和可扩展的方式来处理对象间的位置和尺寸关系。 总之,尺寸链计算是一种在计算机图形学中常用的方法,通过定义对象之间的关系来计算对象的尺寸和位置。它可以应用于各种场景,提供了方便有效的计算方式。 ### 回答3: 尺寸链计算是指通过一系列的数学运算,计算出物体在不同尺度下的大小关系。具体而言,尺寸链计算常见于图像处理、计算机视觉和机器学习等领域中。 在尺寸链计算中,我们首先需要定义一个参考尺度,例如图像的像素尺度或物体的实际尺度。接下来,我们通过比较物体在不同尺度上的大小关系,计算出它们之间的尺度变化比例。最常见的尺度链计算方法是利用比例尺的概念,根据物体在不同尺度上的像素数量或实际长度,计算出它们之间的比例关系。 例如,假设有一张图像,我们想要计算其中目标物体的尺度链。首先,我们可以选择一个参考尺度,比如目标物体在图像中的像素数量。然后,我们在不同尺度下调整图像的大小,并计算目标物体在每个尺度上的像素数量。通过比较这些像素数量,我们可以计算出物体在不同尺度上的尺度变化比例。 尺寸链计算在计算机视觉中有广泛的应用。例如,在目标检测任务中,我们可以通过计算物体的尺度链,来判断不同尺度下目标物体的特征和位置。这对于实现多尺度目标检测非常重要。 总结而言,尺寸链计算通过比较物体在不同尺度上的大小关系,计算出它们之间的尺度变化比例。它在图像处理、计算机视觉和机器学习等领域中具有重要的应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值