
Forgejo 16.0.5 - عالي - عن بُعد - IDOR - GET /api/v1/user/keys/{id} يعيد مفاتيح SSH ومفاتيح النشر الخاصة بمستخدمين آخرين
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · forgejo-keys-idor
التحليل المكتوب: https://abraxaslabs.tech/research/forgejo-keys-idor
الفئة: IDOR الوصول: عن بُعد
Forgejo 16.0.5 (8d24b7d) - Forgejo
GET /api/v1/user/keys/{id} يقع ضمن مجموعة المستخدم الحالي (reqToken، نطاق المستخدم). لا يزال المعالج يحمّل public_key بواسطة المعرّف الرقمي دون أي تحقق من المالك. يحتوي الجدول نفسه على مفاتيح المستخدمين، ومفاتيح النشر (deploy keys)، والكيانات الأساسية (principals). أما GPG في هذا الإصدار فيفعلها بشكل صحيح: GetGPGKeyForUserByID(ctx, ctx.Doer().ID, id). الحقول الإضافية الخاصة محمية. أما مادة المفتاح العام والعنوان والبصمة فليست محمية. المعرّفات متسلسلة.
رمز read:user يتنقل عبر 1، 2، 3 ويحصي مفاتيح SSH ومفاتيح النشر الخاصة بالآخرين.
| المعرّف | لا يوجد CVE بعد |
| الفئة | IDOR |
| الوصول | عن بُعد (مصادَق عليه عبر read:user / جلسة) |
| CWE | CWE-639 |
| CVSS | عالٍ: 7.5 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N |
| المنتج | Forgejo |
| المتأثر | حتى v16.0.5 (8d24b7d) |
| المصادقة | مصادَق عليه (رمز read:user أو جلسة) |
| الترخيص | GNU Affero GPL v3.0 |
| المختبر | 127.0.0.1 فقط |
يسجّل أو يستخدم أي حساب، ويصدر رمز read:user (أو يستخدم ملف تعريف ارتباط الجلسة)، ويتنقل عبر /api/v1/user/keys/{id}. يحصل على العناوين والبصمات ومادة المفتاح العام لمفاتيح لا يملكها. لا يحصل على المفتاح الخاص. لا يحصل على صدفة (shell). يحصي من يملك الوصول إلى ماذا.
| الصلاحية | الطريقة / نقطة الوصول | الاستطلاع / السلامة / التوافر | مُثبت مختبريًا أو مُستنتج |
|---|---|---|---|
| قراءة عنوان مفتاح SSH العام لمستخدم آخر وبصمته ومادة المفتاح | GET /api/v1/user/keys/{id} بصفة مالك أجنبي | استطلاع (سرية جرد المفاتيح العامة) | مُثبت مختبريًا. عنوان الشاهد FORGEJO-KEYS-IDOR-WITNESS على المعرّف 1؛ قائمة المهاجم لا تحتوي إلا على المعرّف 2 |
| جرد مفاتيح النشر بالطريقة نفسها | المعالج نفسه، صفوف KeyTypeDeploy في public_key (OwnerID 0) | استطلاع | مُستنتج من الجدول. زرع المختبر مفتاح SSH لمستخدم، وليس مفتاح نشر |
| قراءة الكيانات الأساسية لشهادات SSH | المعالج نفسه، صفوف KeyTypePrincipal. يستبعد ListPublicKeys هذا النوع | استطلاع | مُستنتج من الجدول |
| رؤية المفاتيح التي تنتمي إلى مستخدمين محدودين أو خاصين | لا يوجد تحقق من الظهور في هذا البحث | استطلاع | مُستنتج من المعالج |
JSON إضافي (user، key_type، read_only) | appendPrivateInformation فقط إذا كان مديرًا أو مالكًا | استطلاع | مُثبت مختبريًا مغلق: استجابة غير المالك لم تحتوِ على حقل user |
مغلق على هذا المسار: مادة المفتاح الخاص، صدفة (shell)، GET /users/{username}/keys (قائمة عامة مرتبطة باسم المستخدم)، GPG GET /api/v1/user/gpg_keys/{id} (404 على معرّف أجنبي)، DeletePublicKey (403 للمالك/المدير). GET /repos/{owner}/{repo}/keys/{id} عبر المستودعات يعيد 404 عندما لا يتطابق RepoID.
تصحيحات الأمان في v16.0.5 (#14370) كانت RCE عبر git-apply وCSRF في OpenID. لم تغلق هذا البحث. من الفئة نفسها مثل gitea-user-keys-idor، ولا يزال مفتوحًا هنا بشكل مستقل.
ثبّتت Forgejo v16.0.5 بعد موجة 2026-09. كان Gitea 1.27.3 لا يزال يحتوي على هذا البحث. لقد تباعدت Forgejo، لذا أعدت قراءة معالج مفاتيح المستخدم الحالي بجانب GPG بدلًا من نسخ حزمة Gitea. GPG يعيد 404 على معرّف أجنبي. أما SSH فلا.
المسارات الخاطئة المسجّلة بالفعل: التعامل مع قائمة المهاجم نفسه على أنها التسريب (وهي ليست كذلك - القائمة محدودة النطاق، بينما GET-by-id ليس كذلك)؛ التعامل مع DISABLE_REGISTRATION=true على المثبّت على أنه إغلاق (أي حساب موجود يكفي)؛ صدفة عكسية. مسرح.
python3 forgejo-keys-idor-Abraxas-Labs.py
أو:
cd lab
./run.sh
استهدف فقط http://127.0.0.1:19310. الصورة codeberg.org/forgejo/forgejo:16.0.5. حسابان. الشاهد FORGEJO-KEYS-IDOR-WITNESS.
IOC planted victim-id=1 attacker-id=2
IOC attacker-list status=200 ... title=attacker-own-key
IOC get id=1 status=200 ... FORGEJO-KEYS-IDOR-WITNESS
IOC gpg-neg id=1 status=404
SUCCESS forgejo-keys-idor victim-id=1 get-http=200 list-has-id=no gpg-http=404 FORGEJO-KEYS-IDOR-WITNESS
404 ما لم يكن key.OwnerID == ctx.Doer().ID (أو مسؤول الموقع). ارفض KeyTypeDeploy / KeyTypePrincipal على هذا المسار. طابِق GetGPGKeyForUserByID.
GetPublicKeyGNU Affero GPL v3.0. راجع LICENSE. مختبر loopback فقط. دون أي ضمان.