JavaScript prototype chain pollution

foreword

When browsing a certain forum, I saw the JavaScript prototype chain pollution vulnerability for the first time. At that time, I was very curious. At that time, I always thought that js was a front-end language. Even if there were loopholes, they were aimed at the front-end and would not harm the back-end. Therefore, I thought that such loopholes should not be harmful. But when I saw his vulnerability and the ability to execute arbitrary commands, I realized that it might be a bit simple. js can also be used as a back-end language. This article will take a look at this vulnerability.

What is the JavaScript prototype chain?

Since the name of the vulnerability is JavaScript prototype chain pollution, we must first understand what the JavaScript prototype chain is.

As we know, Javascrip's complex types are object types (Object), and js is not a completely object-oriented programming language. Then for object programming, object inheritance should be considered.

The core of js to achieve inheritance is the prototype chain . What I understand is that the existence of the prototype chain is the inheritance mechanism in js, which ensures that methods and properties in functions or objects can be passed down.

js uses constructors to create objects, as follows, we can define a class through constructors:

// 构造函数
function Person(name, age) {
    this.name = name;
    this.age = age;
}

// 生成实例
const p = new Person('zhangsan', 18);

1692167778_64dc6e62b659f0a4498b9.png!small?1692167779350

You can see that in addition to the two properties we defined, this class also has a prototype property. prototype points to the prototype object of the function, which is an explicit prototype property that only functions have.

prototype also has two properties:

constructor: Points to the constructor of the prototype

prototype: points to the prototype of Object

There is a _proto_ in the properties of the prototype, so what is the relationship between this _proto_ and the prototype?

1692167810_64dc6e826449231561148.png!small?1692167811088

The prototype prototype is an attribute of the class, and all objects instantiated with the class will have all the contents of this attribute, including variables and methods. For example, the p object in the above figure inherently has the properties and methods of the Person class.

We can access the prototype of the Person class through Person.prototype, but the objects instantiated by Person cannot access the prototype through prototype. At this time, it's time for __proto__ to debut.

That is, classes can use prototype to access the prototype of the class, and instantiated objects can use _proto_ to access the prototype attribute of the class where the object is located.

Summarize:

In fact, we only need to understand one thing. The JavaScript prototype chain is the core of inheritance in js. JS objects will execute other prototypes, and the final prototype pointed to is null. Finally, let’s summarize the prototype chain

1) js is inherited through the prototype chain.

2) All class objects will have properties and methods in the prototype when they are instantiated

3) Classes can use prototype to access the prototype object of the class, and instantiated objects can access the prototype object of the class through _proto_

let f = new Foo();
f.constructor === Foo;
f._proto_ === Foo.prototype
f._proto_ === Foo.prototype
Foo._proto_ === Function.prototype

prototype chain pollution

After understanding the relevant knowledge of the prototype chain, we can take a look at what is the prototype chain pollution vulnerability.

As mentioned above, the __proto__ of the instantiated object points to the prototype of the class. So, if we modify the value in the instantiated object __proto__, can we modify the value in the class? Is it possible to affect all objects from the same class and parent class as this object?

In fact, this is the principle of prototype chain pollution. By modifying the value in __proto__ of the instantiated object, we pollute the class ontology, which in turn affects all objects from the same class and parent class as this object.

There is such an example on God's blog to illustrate prototype chain pollution:

1692167987_64dc6f332874455dd5d81.png!small?1692167987836

Real-world use of analytics

In actual situations, we may only be able to control some parameters, so how can we assign values ​​to __proto__?

To assign a value to __proto__, __proto__ is required to be passed in as a variable and used as a key name. This situation generally occurs in the following three scenarios:

  • object merge
  • Object clone (in fact, the kernel is to merge the object to be operated into an empty object)
  • When the path finds the attribute and then modifies the attribute

Let's borrow an example from P God's article to see the specific operation. The original link is: In-depth understanding of JavaScript Prototype pollution attacks | Farewell Song

Taking the object merge as an example, we imagine a simple merge function:

function merge(target, source) {
    for (let key in source) {
        if (key in source && key in target) {
            merge(target[key], source[key])
        } else {
            target[key] = source[key]
        }
    }
}

In the process of merging, there is an assignment operation target[key] = source[key], so if the key is __proto__, can the prototype chain be polluted?

let o1 = {}
let o2 = {a: 1, "__proto__": {b: 2}}
merge(o1, o2)
console.log(o1.a, o1.b)

o3 = {}
console.log(o3.b)

As a result, the merge succeeds, but the prototype chain is not polluted:

1692168050_64dc6f7280e79c362a397.png!small?1692168051194

This is because, in the process of creating o2 with JavaScript (let o2 = {a: 1, "__proto__": {b: 2}}), __proto__ already represents the prototype of o2, and at this time traverse all the key names of o2 , what you get is [a, b], __proto__ is not a key, and naturally the prototype of Object will not be modified. It can also be seen from the figure below that in o1, parameter b does not appear in the prototype.

1692168062_64dc6f7e3ea57daf7bf33.png!small?1692168062943

So, how do you get __proto__ to be considered a key name?

We change the code to the following:

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)

It can be seen that the newly created o3 object also has the b attribute, indicating that the Object has been polluted

1692168090_64dc6f9ae493107bec1d4.png!small?1692168091483

This is because, in the case of JSON parsing, __proto__ will be considered a real "key name" instead of a "prototype", so this key will exist when traversing o2.

Let's look at o1 again and find that the b attribute is defined in the prototype.

1692168096_64dc6fa0980dab3967fd7.png!small?1692168097212

The merge operation is the most common operation that may control the key name, and it is also the most vulnerable to prototype chain attacks. This problem exists in many common libraries.

js prototype chain pollution vulnerability analysis

Next, use a cve vulnerability to take a closer look at this vulnerability.

There is a prototype pollution vulnerability CVE-2019-11358 in jQuery before version 3.4.0, and the PoC is as follows.

//代码如下,如果从前端接收一个json内容,传到后端。
//json内容:JSON.parse('{"__proto__": {"z": 123}}')

const json1 = ajax();  
jQuery.extend(true, {}, JSON.parse(json1));
console.log( "test" in {} ); // true

The jQuery.extend() function is used to merge the contents of one or more objects into the target object

$.extend( [deep ], target, object1 [, objectN ] )

parameter

describe

deep

optional. The Boolean type indicates whether to merge objects deeply, and the default is false. If the value is true, and a property with the same name of multiple objects is also an object, the properties of this "property object" will also be merged.

target

Object type target object, the member properties of other objects will be attached to this object.

object1

optional. The first object of type Object to be merged.

objectN

optional. The Nth merged object of Object type.

Let's take a look at how the actual code is written.

First download jQuery, here is version 3.3.0

GitHub - jquery/jquery at 3.3.0

The extend function can be found in the src/core.js file. After reading the source code, you can find that this function just fits the concept of merging data mentioned above, so let's see if it will be polluted?

1692168161_64dc6fe1e3ff617f47974.png!small?1692168162655

Let's debug this program dynamically:

Introduce jQuery script and set breakpoint for debugging

1692168167_64dc6fe7b978b4973c2cd.png!small?1692168168393

First judge whether to perform deep copy according to the first parameter, and then perform the first cycle to obtain the parameter as __proto__

1692168172_64dc6fecc462985824a7e.png!small?1692168173522

In the second cycle, assign parameters in __proto__

1692168177_64dc6ff18c0335618e4f2.png!small?1692168178185

Now look at the prototype has been contaminated

1692168182_64dc6ff620c4ded5d0a06.png!small?1692168182716

Summarize

It can be said that the principle of js prototype chain pollution is not too difficult to understand, the key is how to use it in practice. I have also read a lot of articles about this vulnerability. Their ideas are really powerful. I still have a lot to learn, and I will share with you.

Due to my limited level, there may be some mistakes in the article. Welcome everyone to correct me, thank you very much. If you have any good ideas, welcome to share, thank you~~

reference link

JavaScript Prototype Chain Pollution Principle and Analysis of Related CVE Vulnerabilities- FreeBuf Network Security Industry Portal

In-depth understanding of JavaScript Prototype pollution attacks | Farewell Song

Re-exploring JavaScript prototype chain pollution to RCE - Prophet Community

Exploitation of Node.js Prototype Chain Pollution- FreeBuf Network Security Industry Portal
 

Finally, recommend an application development artifact

About the current low-code is very active in the technical field!

What is low code? A set of digital technology tool platforms can realize rapid construction, data arrangement, connection ecology, middle-end services, etc. based on more efficient methods such as graphical drag and drop and parameterized configuration. Realize scenario application innovation in digital transformation with little or no code. It can alleviate or even solve the contradiction between supply and demand caused by huge market demand and traditional development productivity, and is a product of the trend of cost reduction and efficiency increase in the process of digital transformation.

An easy-to-use low-code platform - JNPF rapid development platform. In recent years, it has been outstanding in terms of market performance and product competitiveness, and adopts the latest mainstream front-to-back separation framework (SpringBoot+Mybatis-plus+Ant-Design+Vue 3 ) . The code generator has low dependence, flexible expansion capability, and can flexibly realize secondary development.

In order to support application development with higher technical requirements, the enterprise-level low-code platform represented by JNPF has almost no difference from traditional software development from database modeling, Web API construction to page design. For the repetitive work of the "addition, deletion, modification and query" function, partners who have not yet learned about low-code can try to understand it.

Application: https://www.jnpfsoft.com/?csdn

With it, developers can easily get started during the development process and make full use of the experience accumulated in the traditional development mode. Therefore, low-code platforms are of great help to programmers.

Guess you like

Origin blog.csdn.net/wangonik_l/article/details/132560491
Recommended