Skip to content
KitploitKITPLOIT
उपकरणब्लॉग
जमा करें
उपकरणब्लॉग
जमा करें

हैकिंग, पेनटेस्ट और साइबर सुरक्षा उपकरण आपके सुरक्षा शस्त्रागार के लिए!

Kitploit हैकिंग, साइबर सुरक्षा और पेंटेस्टिंग टूल्स की एक निर्देशिका है। कमजोरियों को खोजने, सिस्टम का विश्लेषण करने, परीक्षण को स्वचालित करने और अपनी सुरक्षा को मजबूत करने के लिए नवीनतम प्रोजेक्ट अपडेट खोजें।

··फ़ीड·संपर्क·गोपनीयता·© 2026 Kitploit

टूल निर्देशिका

श्रेणियाँ

सभी श्रेणियाँ देखें
Loading categories
CVE-2026-18963-Exploit — Keycloak CVE-2026-18963 के लिए एक्सप्लॉइट जो रीसेट-क्रेडेंशियल बाईपास के माध्यम से बिना प्रमाणीकरण के खाता अधिग्रहण सक्षम करता है। इसमें सुरक्षित पहचान, गैर-विनाशकारी प्रमाण, पूर्ण अधिग्रहण, उपयोगकर्ता नाम गणना, और कमजोर तथा पैच किए गए संस्करणों वाला एक लैब शामिल है। | Kitploit
उपकरण/GitHubGitHub/snizi/cve-2026-18963-exploit
प्रमाणीकरण और प्राधिकरणभेद्यता विश्लेषणशोषणवेब एप्लिकेशन शोषणपेनिट्रेशन टेस्टिंग
GitHubsnizi/cve-2026-18963-exploit

CVE-2026-18963-Exploit

Keycloak CVE-2026-18963 के लिए एक्सप्लॉइट जो रीसेट-क्रेडेंशियल बाईपास के माध्यम से बिना प्रमाणीकरण के खाता अधिग्रहण सक्षम करता है। इसमें सुरक्षित पहचान, गैर-विनाशकारी प्रमाण, पूर्ण अधिग्रहण, उपयोगकर्ता नाम गणना, और कमजोर तथा पैच किए गए संस्करणों वाला एक लैब शामिल है।

सबसे लोकप्रिय

सभी देखें →

हमारे समुदाय द्वारा सबसे अधिक उपयोग किए जाने वाले उपकरण खोजें।

सभी उपकरण खोजें

हमारे उपकरणों का संग्रह ब्राउज़ करें

सभी उपकरण देखें →
साझा करें
रिपॉजिटरी देखें
714 दिन पहलेअभी तक समीक्षित नहीं

CVE-2026-18963 — Keycloak reset-credentials बाईपास → बिना प्रमाणीकरण के खाता अधिग्रहण

CVE Affected Python Dependencies

केवल एक उपयोगकर्ता नाम या ई-मेल पता जानकर, एक अनधिकृत हमलावर किसी भी 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

root@kitploit:~
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


विषय-सूची

  • 1. मूल कारण
  • 2. प्रभावित संस्करण (लेगेसी शाखाओं सहित)
  • 3. लैब
  • 4. उपयोग
    • 4a. सुरक्षित पहचान (--safe-check) — यहाँ से शुरू करें
    • 4b. गैर-विनाशकारी प्रमाण (--check)
    • 4c. पूर्ण अधिग्रहण
    • 4d. यूज़रनेम एन्यूमरेशन (--enum)
  • 5. कस्टम लॉगिन थीम
  • 6. ज्ञात अंतर — PKCE
  • 7. किया गया सत्यापन
  • 8. निवारण
  • 9. पहचान
  • लेखक

1. मूल कारण

दो दोष श्रृंखलाबद्ध हैं। अकेले कोई भी शोषण योग्य नहीं है।

दोष 1 — एक असीमित, स्टिकी फ्लैग

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);

root@kitploit:~
नोट एक **नंगा बूलियन है जिसमें यह दर्ज नहीं रहता कि उसे किस 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> को अंकित करता है और ब्राउज़र को लॉगिन पेज पर फोर्क करता है। स्थगित निष्पादन बिल्कुल ई-मेल गेट है।

दोष 2 — ई-मेल गेट एक्शन टोकन की जाँच कभी नहीं करता

`services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetCredentialEmail.java````java @Override public void action(AuthenticationFlowContext context) { context.getUser().setEmailVerified(true); context.success(); }

root@kitploit:~
बिना शर्त। कोई जाँच नहीं करता कि प्रवाह एक वैध एक्शन टोकन द्वारा फिर से शुरू किया गया था,
इसलिए `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 पैरामीटर किसी भी बिंदु पर नहीं।

फिक्स (PR #51844)

  • नोट अब 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 के साथ विफल हो जाता है।

2. प्रभावित संस्करण (लेगेसी लाइनों सहित)

इस CVE के लिए "लेगेसी" का क्या अर्थ है

  • लेगेसी रिलीज़ अपने आप सुरक्षित नहीं हैं — वे एक विशिष्ट कारण से सुरक्षित हैं। स्टिकी-बूलियन नोट 26.0.0 में कमिट 6a9e60bb द्वारा, जिसने "Try another way" प्रमाणीकरण-चयनकर्ता स्क्रीन को रीसेट फ्लो में जोड़ा। इससे पुरानी किसी भी चीज़ में केवल उस कोड पथ का अभाव है। इसमें पुराने WildFly-आधारित वितरण और RH-SSO 7.x, जो इस बग से प्रभावित नहीं हैं जबकि वे जीवन-अंत पर हैं और कई अन्य कमजोरियों के लिए संवेदनशील हैं। किसी लेगेसी बिल्ड पर बने रहना निवारण नहीं है।
  • लेगेसी 26.x लाइनें असली समस्या हैं। 26.7.2 एकमात्र फिक्स रिलीज़ है जो कम्युनिटी ट्रेन के लिए प्रकाशित की गई है। अगर कोई डिप्लॉयमेंट 26.0 – 26.6 पर है, तो उस लाइन पर कोई पैच रिलीज़ नहीं है — फिक्स के लिए माइनर-वर्जन अपग्रेड आवश्यक है, न कि पॉइंट रिलीज़। 26.4.15 / 26.6.6 टैग विक्रेता बैकपोर्ट हैं और कम्युनिटी इमेजों के साथ विनिमेय नहीं हैं।
  • क्योंकि बहुत सारे लंबे समय से चले आ रहे डिप्लॉयमेंट संगतता कारणों से पुराने 26.x पर टिके हुए हैं, "हम अपनी लाइन पर पूरी तरह पैच किए हुए हैं" यहाँ एक आम और गलत धारणा है। चल रहे बिल्ड की जाँच करें, अद्यतन नीति की नहीं।

पूर्वशर्तें: रिएल्म में फॉरगॉट पासवर्ड सक्षम है और उसका जुड़ा हुआ रीसेट-क्रेडेंशियल्स फ्लो अंतर्निहित reset-credential-email प्रमाणीकरणकर्ता का उपयोग करता है।


3. लैब

यह रिपो एक भेद्य और एक पैच किया हुआ Keycloak दोनों शामिल करता है, जो समान रिएल्म आयात करते हैं, साथ ही रीसेट मेल कैप्चर करने के लिए Mailpit भी शामिल है — ताकि आप देख सकें कि मेल आता है और अपठित रहता है, जबकि खाते पर कब्ज़ा कर लिया जाता है।```bash cd lab docker compose up -d

root@kitploit:~
| 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।


4. उपयोग

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

root@kitploit:~
`--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; }

root@kitploit:~
`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) घटित होते हैं — इन्हें एंगेजमेंट स्कोप में दर्शाएँ:

  • वास्तविक पीड़ित को एक पासवर्ड-रीसेट ई-मेल भेजा जाता है (चरण 4 एक वास्तविक रीसेट अनुरोध है), और
  • कमजोर action() खाते पर emailVerified = true सेट कर देता है।

कोई भी क्रेडेंशियल संशोधित नहीं होता। एक समर्पित परीक्षण खाते का उपयोग करें।

4c. पूर्ण अधिग्रहण

केवल प्रयोगशाला या स्पष्ट रूप से अधिकृत प्रदर्शन हेतु।```bash python3 cve_2026_18963_poc.py
--base http://localhost:8080 --realm poc --client-id poc-app
--victim victim --new-password 'PoCPassw0rd!1'

root@kitploit:~
निकास `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 ने जानबूझकर लागू किया था। टेकओवर के साथ-साथ इसे अपने स्वयं के निष्कर्ष के रूप में लिखना उचित है, और यह "हमारे उपयोगकर्ता नाम अनुमान लगाने योग्य नहीं हैं" को एक शमन कारक के रूप में समाप्त कर देता है।


5. कस्टम लॉगिन थीम

कोई भी गंभीर तैनाती एक कस्टम लॉगिन थीम के साथ आती है, और कस्टम थीम स्टॉक एलिमेंट आईडी (kc-form-login, kc-reset-password-form, kc-select-credential-form, kc-passwd-update-form) का नाम बदल देती हैं या उन्हें हटा देती हैं। एक उपकरण जो उन आईडी पर आधारित होता है, ठीक उन्हीं तैनातियों पर गलत नकारात्मक रिपोर्ट करता है जो सबसे महत्वपूर्ण हैं — यह उपकरण, पुनर्लेखन से पहले, ऐसा ही करता था। जंगल में देखी गई थीम id="login-form" जैसी आईडी का उपयोग करती हैं और एक फॉरगॉट पासवर्ड एंकर के साथ आती हैं जिसका href खाली होता है।

इसलिए यह PoC किसी भी चीज़ पर आधारित नहीं है जिसे थीम नियंत्रित करती है:

  • केवल फ़ॉर्म एक्शन URL। हर निर्णय पृष्ठ पर मौजूद फ़ॉर्म के action= से लिया जाता है — login-actions/reset-credentials, login-actions/authenticate, login-actions/required-action — और उनके अंदर मौजूद execution क्वेरी पैरामीटर से। वे पथ Keycloak की अपनी LoginActionsService द्वारा उत्पन्न होते हैं, थीम द्वारा नहीं।
  • कोई एलिमेंट आईडी नहीं। स्रोत में grep करें: इसमें एक भी kc-* आईडी नहीं है।
  • कोई संदेश पाठ नहीं। प्रतिक्रिया स्ट्रिंग्स स्थानीयकृत हैं — एक जर्मन रीम "Reset Credential nicht erlaubt" का उत्तर देती है, और "You should receive an email" पर मिलान करना हर गैर-अंग्रेज़ी रीम पर टूट जाता है।
  • यह कभी भी थीम वाले "फॉरगॉट पासवर्ड" लिंक का अनुसरण नहीं करता। लिंक अनुपस्थित, खाली, JavaScript-संचालित, या पूरी तरह से Keycloak के बाहर कहीं और इंगित कर सकता है — इनमें से कोई भी यह नहीं बताता कि एंडपॉइंट पहुँच योग्य है या नहीं। उपकरण /realms/<realm>/login-actions/reset-credentials?client_id=…&tab_id=… का निर्माण करता है और सीधे उसकी जाँच करता है, tab_id को लॉगिन पृष्ठ द्वारा प्रदर्शित किसी भी फ़ॉर्म से लेता है।

यदि कोई लक्ष्य अभी भी INCONCLUSIVE लौटाता है, तो --verbose --dump out.html के साथ चलाएँ और प्रतिक्रिया पढ़ें — उपकरण जानबूझकर अनुमान लगाने से इनकार करता है।


6. ज्ञात अंतर — PKCE

एक क्लाइंट जो PKCE लागू करता है चरण 1 को Missing parameter: code_challenge_method के साथ अस्वीकार कर देता है। इसे INCONCLUSIVE (निकास 3) के रूप में रिपोर्ट किया जाता है, कभी भी पास के रूप में नहीं। जब तक PKCE समर्थन नहीं आता, एक रीम जिसका एकमात्र उपयोग योग्य सार्वजनिक क्लाइंट PKCE अनिवार्य करता है, उसे इस उपकरण से जाँचा नहीं जा सकता — अंतर्निहित account क्लाइंट आज़माएँ, जो सामान्य रूप से इसे लागू नहीं करता।


7. किए गए सत्यापन

नीचे हर रन इस रिपो में मौजूद लैब के विरुद्ध है, प्रकाशित कोड का उपयोग करके।

एडवाइज़री पाठ से परे दो निष्कर्ष ध्यान देने योग्य हैं:

  1. बिना ई-मेल पते वाले खाते शोषण योग्य हैं। ResetCredentialEmail.authenticate() forkWithSuccessMessage पथ लेता है जब user.getEmail() null होता है, जो फिर भी case FORK: के माध्यम से निष्पादन को पार्क करता है। SMTP भेजने की विफलता के लिए भी यही बात लागू होती है — एक टूटा या अनुपस्थित मेल सर्वर कोई शमन नहीं है। यह सीधे AD/LDAP-फेडरेटेड रीम के लिए मायने रखता है, जहाँ खातों में अक्सर कोई मेल विशेषता नहीं होती।
  2. फ्लो पूरा करने से हमलावर पीड़ित के रूप में लॉग इन हो जाता है। अंतिम रीडायरेक्ट एक वैध OIDC प्राधिकरण कोड ले जाता है, इसलिए पासवर्ड फ़ॉर्म सबमिट होते ही खाता समझौता हो जाता है।

MFA कोई शमन नहीं है। डिफ़ॉल्ट reset-credentials फ्लो में कोई OTP चरण नहीं है, और एक बार पार करने के बाद, हमलावर पीड़ित के पंजीकृत कारकों को हटा सकता है।


8. उपचार

समाधान: अपग्रेड करें। सामुदायिक बिल्ड के लिए 26.7.2, या आपकी सदस्यता से मेल खाने वाला विक्रेता बैकपोर्ट टैग। नीचे सब कुछ एक अस्थायी उपाय है।

अंतरिम शमन, सर्वोत्तम पहले:

  1. फॉरगॉट पासवर्ड अक्षम करें प्रति रीम (रीम सेटिंग्स → लॉगिन)। प्रभावी पुष्टि — फ्लो HTTP 400 लौटाता है और इसमें प्रवेश नहीं किया जा सकता। हर रीम की जाँच करें, master सहित।
  2. बाउंड reset-credentials फ्लो में रीसेट पासवर्ड निष्पादन अक्षम करें। काम करता है, लेकिन लॉगिन पृष्ठ अभी भी लिंक प्रदान करता है, इसलिए UX खराब है। उपयोगी जहाँ एक कस्टम थीम रीम स्विच को अनदेखा करती है।
  3. रीसेट फ्लो में ई-मेल चरण के बाद एक आवश्यक प्रमाणक (OTP/WebAuthn) जोड़ें। यह बायपास को बंद नहीं करता — यह केवल पूर्ण टेकओवर को उन खातों तक सीमित करता है जिन्होंने वास्तव में उस कारक को नामांकित किया है।

जिन रीम का बाउंड रीसेट फ्लो पूरी तरह से कस्टम है और कभी भी reset-credential-email को लागू नहीं करता, वे इस पथ के माध्यम से शोषण योग्य नहीं हैं।


9. पहचान

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.026.0.0 – 26.0.17कोई नहीं
26.126.1.0 – 26.1.5कोई नहीं
26.226.2.0 – 26.2.16कोई नहीं
26.326.3.0 – 26.3.5कोई नहीं
26.426.4.0 – 26.4.1426.4.15 (विक्रेता बैकपोर्ट टैग)
26.526.5.0 – 26.5.7कोई नहीं
26.626.6.0 – 26.6.526.6.6 (विक्रेता बैकपोर्ट टैग)
26.726.7.0 – 26.7.126.7.2
Exitनिर्णयअर्थ
0असुरक्षितपार्क किया गया ईमेल गेट सर्व किया गया — यही बग है
2पैच किया गयाफ्लो लॉगिन पर चला गया और वहीं रुका (फिक्स #51844 मौजूद है)
2शमितरीसेट-क्रेडेंशियल्स अप्राप्य है — पासवर्ड भूल गए बंद है। यह पैच नहीं है।
3अनिर्णायकअपरिचित प्रतिक्रिया — इसे पास के रूप में न पढ़ें
परीक्षणलक्ष्यपरिणाम
--safe-check26.7.1VULNERABLE, निकास 0 — ई-मेल गेट परोसा गया (execution ≠ choose-user)
--safe-check26.7.2PATCHED, निकास 2 — लॉगिन पर फोर्क किया और वहीं रहा
--safe-check, फॉरगॉट पासवर्ड बंद26.7.2MITIGATED, निकास 2 — HTTP 400, फ्लो अप्राप्य
पूर्ण टेकओवर26.7.1निकास 0 — पासवर्ड सेट, OIDC कोड जारी, पासवर्ड ग्रांट पुष्टि करता है
पूर्ण टेकओवर26.7.2निकास 2 — चरण 5 पर अवरुद्ध, खाता अछूता
--check26.7.1UPDATE_PASSWORD तक पहुँचा; बाद में पासवर्ड अपरिवर्तित सत्यापित
--enum26.7.1victim और [email protected] VALID, does-not-exist INVALID
टेकओवर के बाद क्रेडेंशियल स्थिति26.7.1नया पासवर्ड → 200, पुराना पासवर्ड → 400
अवरुद्ध रन के बाद क्रेडेंशियल स्थिति26.7.2पुराना पासवर्ड → 200, हमलावर पासवर्ड → 400
पीड़ित का मेलबॉक्सMailpitरीसेट मेल वितरित और अपठित; एक्शन-टोकन लिंक कभी नहीं लाया गया