
Plausible Analytics master d44e104 - عالية - عن بُعد - IDOR - PUT traffic-change-notification site_id إسناد جماعي
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · plausible-traffic-notify
Plausible Analytics إصدار المجتمع، فرع GitHub الرئيسي d44e104ae3943a9240d5cb6b62e67dff0f069d3a (2026-10-16) - Plausible Insights OÜ
التصنيف: IDOR (إسناد جماعي). الوصول: عن بُعد (مالك / مسؤول / محرر لموقع يتحكم به المهاجم مسبقًا).
لا يزال Plausible.Site.TrafficChangeNotification.changeset/2 يُسند :site_id. يقوم SiteController.update_traffic_change_notification/2 بتحميل السجل عبر نطاق المسار المصرّح به، ثم Repo.update! لخريطة العميل. يقع المسار PUT /sites/:domain/traffic-change-notification/:type تحت :browser + CSRF + AuthorizeSiteAccess [:owner, :admin, :editor, :super_admin]. نموذج HTML يرسل threshold فقط. ومع ذلك لا يزال Phoenix يقبل مفاتيح إضافية.
أصلح whoareme الخطأ 02 في Shield / Goal site_id بالطريقة نفسها: ربط socket.assigns.site.id، وإيقاف إسناد :site_id. لم يكن هذا المتحكم ضمن تلك الدفعة. التفعيل (POST .../enable) يضع site_id: site.id من assigns. يقوم المهاجم بالتفعيل على موقعه الخاص، ثم يرسل PUT بـ traffic_change_notification[site_id]=<victim_pk>. فهرس فريد (site_id, type). التثبيت الافتراضي لا يحتوي على سجل spike/drop، لذا تنجح عملية التحديث ويصبح السجل مملوكًا للضحية. اسم الجدول قديم spike_notifications.
محرر لموقعه الخاص يعيد إسناد سجل إشعار spike/drop إلى موقع ضحية. يبقى المستلمون صندوق بريد المهاجم. يرسل Oban بريدًا للمهاجم حول حركة مرور الضحية.
| المعرّف | لا يوجد CVE بعد |
| CWE | CWE-915 / CWE-639 |
| CVSS | عالٍ: 7.1 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:L |
| المنتج | Plausible Analytics |
| المتأثر | فرع GitHub الرئيسي d44e104ae3943a9240d5cb6b62e67dff0f069d3a (2026-10-16). آخر وسم CE v3.2.1 (e4f5a87a5570bd61605217e7ceb376636db8eddb، 2026-05-15) متأخر بخمسة أشهر. CE + EE (lib/، وليس extra/lib). |
| المصادقة | مالك / مسؤول / محرر لموقع يتحكم به. المشاهد لا يستطيع. CSRF مطلوب (IDOR بنفس الجلسة). |
| الترخيص | GNU Affero GPL v3.0 |
| المختبر | 127.0.0.1:18183 (http) 18184 (postgres) 18185 (clickhouse http) فقط |
المتبقي #2 من بقايا Plausible Analytics. نفس التثبيت، حزمة أخرى: plausible-editor-invite (تسريب HTML الخاص بـ People لنقل nanoid إلى المحررين). هذه الحزمة هي الشقيقة Shield/Goal التي لا تزال تُسند :site_id.
مالك أو مسؤول أو محرر لأي موقع يتحكم به مسبقًا. يحتاج إلى ملف تعريف ارتباط جلسة ورمز CSRF من تلك الجلسة. لا يحتاج إلى عضوية على الضحية. لا يرسل PUT إلى نطاق مسار الضحية (ذلك يعيد 404). يرسل PUT إلى نطاقه الخاص مع مفتاح أساسي صحيح site_id أجنبي.
جدول الصلاحيات (شامل). نفس المعيار كـ Signal-Server Dropwizard admin: الطريقة + المسار، ما يمنحه ذلك الاستدعاء، الاستطلاع مقابل السلامة مقابل التوفر، مُثبت مختبريًا مقابل مُستنتج، السطح المجاور الذي يبقى مغلقًا.
| المحور | الطريقة + المسار | ما يمنحه | المصدر |
|---|---|---|---|
| السلامة | POST /sites/:attacker_domain/traffic-change-notification/:type/enable ثم PUT /sites/:attacker_domain/traffic-change-notification/:type مع traffic_change_notification[site_id]=<victim_pk> | إعادة ربط صف spike_notifications الخاص بالمهاجم إلى victim.sites.id. يبقى المستلمون عنوان المهاجم. يملك خانة (site_id, type) الفريدة. العتبة يختارها المهاجم (استخدم المختبر 1). | مُثبت مختبريًا. الصف 1 نقل site_id من 2 → 1، المستلمون {[email protected]} |
| الاستطلاع | بريد Oban TrafficChangeNotifier إلى notification.recipients | الموضوع Traffic spike on <victim.domain>. النص: عدد الزوار الحالي، أفضل 3 مصادر، أفضل 3 صفحات. الإرسال الأول فوري (last_sent nil). يتكرر كل 12 ساعة على الأكثر. العتبة 1 تُنتج بريدًا كلما كان لدى الضحية أي زائر حالي. تُحذف روابط HTML للوحة التحكم / التثبيت في البريد ما لم يكن المستلم عضوًا في فريق/ضيفًا (المهاجم ليس كذلك). | مُستنتج من مصدر المُخطر. لم يُلتقط البريد في المختبر (MAILER_ADAPTER=Bamboo.LocalAdapter) |
| التوافر | POST .../enable الخاص بالضحية لنفس النوع | يرفضه القيد الفريد (site_id, type). لا تستطيع الضحية تفعيل الميزة حتى يزول الصف المزروع. | المصدر (unique_constraint) |
| التوافر | disable الخاص بالضحية (delete_all حسب site_id) | تستطيع الضحية مسح الصف المزروع إن لاحظت المستلم الإضافي. | المصدر (disable_traffic_change_notification) |
يبقى مغلقًا على هذا التثبيت
| المحور | الطريقة + المسار | لماذا هو مغلق |
|---|---|---|
| السلامة | PUT /sites/:victim_domain/traffic-change-notification/:type | نطاق المسار هو AuthorizeSiteAccess. المهاجم ليس عضوًا. مُثبت مختبريًا 404. attacker-not-member-of-victim=1 |
| السلامة | كتابة Shield / Goal / funnel / segment / shared-link | رقّع whoareme Bug 02 معالجات cast :site_id تلك. فهي تربط assigns. |
| الاستطلاع | تفريغ ClickHouse، Stats API، HTML لوحة التحكم | لا عضوية، لا رابط مشترك. يحذف بريد المُخطر روابط لوحة التحكم لغير العضو. |
| السلامة | استقبال tracker | أصلاً POST /api/event غير مُصادق مع نطاق يختاره العميل. ليس هذه البقايا. |
| السلامة | Repo.update! عندما يكون لدى الضحية ذلك النوع بالفعل | 500 على القيد الفريد (site_id, type). التثبيت الافتراضي لا يحتوي صفًا، لذا ينجح الزرع الأول. |
| السلامة | مشاهد موقع المهاجم | AuthorizeSiteAccess هو مالك/مدير/محرر. لا يستطيع المشاهد. |
| السلامة | صدفة نظام التشغيل، LiveView للمشرف الأعلى | مغلق. لا صدفة. |
لا أدّعي تفريغ ClickHouse، أو reverse shell، أو تسجيل الدخول إلى لوحة التحكم بصفة الضحية. التفريغ هو استطلاع حركة المرور في بريد يتلقاه المهاجم بالفعل: النطاق، الزوار المباشرون، أفضل المصادر، أفضل الصفحات. site_id هو المفتاح الأساسي الصحيح (قابل للتعداد؛ استخدم whoareme site_id=1). لا تُصدره data-* في لوحة التحكم.
علّم whoareme Bug 02 كلاً من Shield وGoal التوقف عن تحويل :site_id. بحثت بـ grep عن cast(.*:site_id المتبقية تحت lib/. كان إشعار تغيّر الحركة لا يزال يحتوي عليها. التفعيل يختم assigns. التحديث يأخذ خريطة العميل. تلك هي البقايا.
يستنسخ run.sh التثبيت إذا كان plausible-lab:d44e104ae3943a مفقودًا، ويشغّل compose مع DISABLE_REGISTRATION=false حتى يتمكن فريقان مستقلان من التسجيل، ويزرع victim.lab (id 1 team 1) وattacker.lab (id 2 team 2)، ويفعّل إشعار الارتفاع على المهاجم، ثم ينفّذ PUT بـ site_id=1.
المنعطفات الخاطئة المسجلة سلفًا: SECRET_KEY_BASE أقصر من 64 بايت (Plug.Session.COOKIE يرفضه)؛ PUT على نطاق مسار الضحية (404، ذلك هو المجاور المغلق)؛ اعتبار التفعيل هو الخلل (التفعيل مُعيَّن بشكل صحيح). مسرح.
python3 plausible-traffic-notify-Abraxas-Labs.py
أو
cd lab
./run.sh