
مختبر إثبات مفهوم يوضح تجاوز مصادقة acceptInvite الخطير في Lago GraphQL الذي يتيح الاستيلاء على الحسابات عبر المؤسسات من خلال قبول الدعوات دون مصادقة.
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · lago-invite-ato
Lago v1.53.0 - GetLago
Mutations::Invites::Accept لا يحتوي على AuthenticableApiUser. أما Create/revoke فيحتويان عليه. Accept لا يحتوي عليه. register_from_invite يحمّل المستخدم عبر بريد الدعوة. إذا كان لهذا الحساب عضويات بالفعل، يتم تجاهل كلمة المرور المُرسَلة. AuthToken.encode(user:) لا يزال يعمل. الـ JWT مُقيَّد بالمستخدم. لا يوجد ادعاء org. يرسل العميل x-lago-organization لأي org ينتمي إليه ذلك المستخدم بالفعل. بما في ذلك org الضحية. createInvite يُعيد بالفعل الـ token إلى المُدعِي.
ادعُ cfo@victim إلى org مؤقت، واقبل الدعوة بنفسك، وستكون ذلك الشخص على كل org يوجد فيه ذلك البريد بالفعل. صندوق البريد لا يتدخل أبدًا. كلمة مرور الضحية دون تغيير.
| ID | لا يوجد CVE بعد |
| CWE | CWE-287، CWE-306 |
| CVSS | حرج: 9.6 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N |
| المنتج | Lago / lago-api |
| المتأثر | حتى v1.53.0 email/password acceptInvite |
| المصادقة | org admin (organization:members:create)؛ تسجيل Cloud كافٍ |
| الترخيص | GNU Affero GPL v3.0 |
| المختبر | 127.0.0.1 فقط |
تحتاج إلى org تتحكم به. تسجيل Cloud كافٍ (LAGO_DISABLE_SIGNUP افتراضيًا false). ادعُ بريد ضحية، واقبل الدعوة دون مصادقة بكلمة مرور وهمية، ثم بدّل الـ header إلى Victim Corp. الفواتير، مفاتيح API، Stripe، المحافظ.
ليس زائرًا عشوائيًا بلا حساب. وليس إعادة تعيين كلمة المرور. تسجيل الدخول الوهمي يفشل. كلمة مرور الضحية الحقيقية لا تزال تعمل. قبول Google/Okta يربط بريد IdP وليس هذه الثغرة. الاستضافة الذاتية أحادية الـ org مع عدم وجود بريد شخص آخر في قاعدة البيانات لا يمنحك تاجرًا آخر. نفس قاعدة البيانات، org اثنان، نفس البريد: نعم يمنحك.
نفس الشجرة مثل Stripe one-time invoice IDOR. ثغرة مختلفة.
قرأت Accept (لا يوجد AuthenticableApiUser)، ثم find_or_initialize_by(email:)، ثم فرع وجود العضويات الذي يتخطى كلمة المرور، ثم AuthToken.encode(user:). ثم قبول Google، الذي يتحقق من google_oidc["email"] == invite.email. قبول email/password لا يربط كلمة مرور مستخدم موجود.
أول عميل ينظر إلى هذا سيدعو عنوانًا غير مستخدم، ويقبله، ويحصل على مستخدم Lago جديد تمامًا بكلمة المرور التي أرسلها. تلك هي الميزة. الدليل هو معرّف مستخدم الضحية الموجود الذي يعود.
المنعطفات الخاطئة المسجلة بالفعل: القبول باستخدام Google/Okta؛ اعتبار createInvite 401 بدون JWT هو القصة كاملة (create مُصادَق عليه، accept ليس كذلك)؛ النظر فقط إلى org المهاجم في currentUser (الدليل هو Victim Corp في القائمة)؛ تسجيل الدخول بكلمة المرور الوهمية (هذا سيعني أن الـ hash قد تم استبداله - المختبر يؤكد أنه لم يحدث)؛ reverse shell. مسرحية. لا صندوق بريد.
ثم: استدعاءان لـ registerUser يزرعان Victim Corp و Attacker Corp. بريد جديد في كل تشغيل حتى لا يُرجع volume متسخ 422 user_already_exists. createInvite على بريد الضحية. acceptInvite دون مصادقة بكلمة مرور وهمية. معرّف المستخدم المُعاد يطابق الضحية. currentUser.organizations يسرد كليهما. تبديل الـ header يُعيد Victim Corp.
cd lab
./run.sh
الهدف فقط http://127.0.0.1:13000. استخدم Stripe IDOR المنفذ 13001. لا يوجد منفذ UI.
IOC victim_password_unchanged
IOC victim_real_password_still_works
SUCCESS LAGO-INVITE-ATO acceptInvite JWT is existing victim; lists Victim Corp; no inbox
إذا كان المستخدم موجودًا بالفعل، اطلب منه المصادقة بنفسه (أو إثبات صندوق البريد / IdP) قبل ربط العضوية. لا تُصدر JWT لمستخدم موجود من accept غير مُصادَق عليه. توقف عن إعادة token الدعوة إلى المُدعِي إذا كان يمثل capability.
accept.rb · accept_service.rb · users_service.rb · create.rb · object.rb · google_service.rbGNU Affero GPL v3.0. راجع LICENSE. مختبر loopback فقط. لا ضمان.