原型链污染(原型链属性改变)

Python原型链污染

去找了一下原理,有如下特征

  1. 方法的层级调用(和ssti相似
  2. 父类与子类

一些方法

  1. waf有对_.的过滤

    转义__init__\\\\.__globals__

    __init__是访问对象初始化方法

    __globals__则是访问全局命名空间。

    双反斜杠 \\\\:

    • 双反斜杠是用来转义反斜杠的。
    • 在字符串中,\\\\实际代表一个单一的反斜杠\
  2. {"key":"__class__\\\\.__init__\\\\.__globals__\\\\.app.router.name_index.__mp_main__\\.static.handler.keywords.file_or_directory","value": "/"}
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    3.

    ### python的一些语句碎片

    ```python
    if key and value and type(key) is str and '_.' not in key:
    pollute = Pollute()
    pydash.set_(pollute, key, value)
    return text("success")

确保keyvalue存在,

key是一个字符串且不包含_.的组合,

然后使用pydash.set_方法在pollute对象中设置属性

pydash.set_

set_ 方法用于在对象中设置或添加属性,支持使用点表示法的路径

1
2
3
4
5
6
import pydash

pollute = {}
pydash.set_(pollute, 'a.b.c', 42)
print(pollute) # 输出: {'a': {'b': {'c': 42}}}

1
2
3
class Pollute:
def __init__(self):
pass#占位符

__init__方法当前没有实现任何初始化逻辑。

在Python中,__init__方法是类的构造函数,用于在实例化对象时初始化对象的属性。它通常接受self参数,代表类的实例。

Javascript的原型链污染

原型==样机

原型链:实例可以通过原型链访问原型对象中的属性和方法。如果实例需要访问的属性或方法在自身上找不到,它就会沿着原型链向上查找父类,直到找到为止。

去了解了一下Javascript的原型链污染https://juejin.cn/post/7201668416170901563

const user = JSON.parse('{"__proto__": {"isAdmin": true}}');

  1. 导致user对象继承isAdmin属性,即使这个属性在原始数据中不存在。
  2. __proto__在JavaScript中,__proto__属性允许你访问或修改对象的原型。通过传递包含__proto__的JSON字符串,你可以操纵创建对象的原型链。

解决方法:

使用安全库:使用设计用来安全处理JSON解析的库,这些库可以检测并防止原型污染。

1
2
const safeParse = require('secure-json-parse');
const user = safeParse.parse('{"__proto__": {"isAdmin": true}}');

原理:

  1. 在 JavaScript 中,每个对象都有一个 __proto__ 属性,它指向该对象的原型。

  2. person1.__proto__ === Person.prototype

person1对象

Person函数

  1. prototype 对象所特有的属性,实例没有

操作: JSON.parse('{"__proto__": {"isAdmin": true}}'),其他见Javascript的原型链污染相关函数解析

目的:修改对象的属性

Javascript的原型链污染相关函数解析

call Animal.call(this, name)

  • this 绑定到当前的Dog实例。
  • name 是传递给Animal构造函数的参数。

通过这种方式,Animal构造函数中的this.name = name将会把name属性赋值给当前的Dog实例,从而实现继承父类属性的目的。

Dog.prototype = Object.create(Animal.prototype);

Object.create(proto, [propertiesObject])

proto: 要作为新对象原型的对象。

propertiesObject(可选): 该对象的可枚举(可选)属性将被作为新对象的自身属性。

Object.create 是 JavaScript 中用于创建一个新对象的方法,新对象的原型是一个指定的对象

Dog.prototype.constructor = Dog;

Dog的构造函数指回Dog,确保constructor属性正确指向。

Object.prototype.toString = function(){……}

修改所有对象的 toString 方法

Object.setPrototypeOf(normalObj, maliciousObj);

使用 Object.setPrototypeOf 方法将 normalObj 的原型设置为 maliciousObj

merge 函数:

Lodash 库的 _.merge 方法来合并对象。Lodash 是一个流行的 JavaScript 工具库,提供了许多有用的函数来处理数组、对象、字符串等。

当使用 merge 函数合并两个对象时,如果这两个对象都有相同的属性,那么 merge 函数会将目标对象中的属性值替换为源对象中的属性值。然而,如果这些属性的值是对象或者数组,那么 merge 函数并不会复制它们的值,而是将它们的引用复制给了目标对象。这样,如果修改目标对象中的这些属性,那么源对象中的这些属性也会被修改,进而污染了原型链。

浅拷贝: 这个 merge 函数实现的是浅拷贝,只会复制 source 对象的第一层属性。如果属性的值是对象,则只会复制对象的引用,而不会递归合并对象的嵌套属性。

1
2
// 修改全局变量中的属性
globalObj.globalProp = 'modified global property';

_.merge 用于递归合并两个或多个对象的属性。它会修改第一个对象并返回该对象。对于同名属性,如果它们的值是对象,那么会递归地合并它们;否则后面的值会覆盖前面的值。

Lodash

安装 Lodash,通过 npm 安装:

1
npm install lodash

然后在代码中引入:

1
const _ = require('lodash');

Object.assign({}, source)

复制source对象的原型对象中的属性和方法

Object.create(proto, [propertiesObject])

eval()函数:

eval()函数是一个全局函数,它将传入的字符串作为 JavaScript 代码进行解析和执行。具有执行任意代码的能力.

1
2
// 使用 eval 函数创建一个函数并在其中访问全局变量
eval('function myFunc() { console.log(globalVar);
1
2
3
var code = "this.__proto__.myProperty = 'Hello World';"; // 向原型对象添加属性
eval(code); // 执行代码
console.log(myObject.myProperty); // Hello World

object.hasOwnProperty(property)

object: 要检查的对象。

property: 要检查的属性名,必须是字符串类型。

hasOwnProperty 是 JavaScript 对象的一个方法,用于检查对象是否具有某个属性作为其自身的属性(而不是从原型链继承的属性)。

merge({}, JSON.parse('{"__proto__": {"isAdmin": true}}'));

{}空对象source 对象包含 __proto__ 属性,并且没有进行安全检查,合并操作会导致整个原型链被污染。最终,这种污染会影响到所有新创建的对象,使它们都包含 isAdmin 属性。

JavaScript中可以触发弹窗的函数

  1. alert() 函数可以在浏览器中弹出一个警告框,用于向用户显示一条消息。

alert('Hello, world!');

  1. confirm() 函数可以在浏览器中弹出一个确认框,用于向用户显示一条消息并询问用户是否继续操作。
1
2
3
4
5
if (confirm('Are you sure you want to delete this item?')) {
// 用户点击了确认按钮,执行删除操作
} else {
// 用户点击了取消按钮,不执行删除操作
}
  1. prompt() 函数可以在浏览器中弹出一个对话框,用于向用户显示一条消息并询问用户输入内容。
1
2
3
4
5
6
let name = prompt('What is your name?');
if (name) {
alert('Hello, ' + name + '!');
} else {
alert('Please enter your name.');
}