
إثبات مفهوم ومختبر لثغرة SSRF مُصادَق عليها في نقطة نهاية ترحيل المستودع في Gitea، حيث يتبع git عمليات إعادة توجيه HTTP إلى git HTTP على الواجهة المحلية ويسرّب الكائنات الداخلية.
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · gitea-git-redir-ssrf
المقال: https://abraxaslabs.tech/research/gitea-git-redir-ssrf
Gitea 1.27.3 - Gitea
IsMigrateURLAllowed هو استدعاء لمرة واحدة لـ net.LookupIP على الرابط الذي كتبته. ثم تمر البايتات عبر git clone --mirror. من المفترض أن يمنع HandleGitCmdHTTPRedirection git من تتبّع تلك القفزة. لكنه لا يفعل شيئًا. التعليق هو الاكتشاف نفسه: فقد تركوا http.followRedirects=false معطّلًا لأن GitLab يعيد 301 بدون .git. استدعاء جلب النسخ المتطابقة (pull-mirror) يستدعي نفس الدالة عديمة الأثر.
يمكن لمستخدم مسجّل الدخول أن يهاجر من مضيف طُعم مدرج في القائمة المسموحة، فيتبع git إعادة التوجيه 302 إلى git HTTP على loopback. فتهبط الكائنات الداخلية في مستودع يملكه هو.
| المعرّف | لا يوجد CVE بعد |
| CWE | CWE-918 |
| CVSS | عالٍ: 7.7 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N |
| المنتج | Gitea |
| المتأثر | حتى v1.27.3 (146cc3e) |
| المصادقة | مصادَق عليه (التسجيل المفتوح افتراضيًا) |
| الترخيص | GNU Affero GPL v3.0 |
| المختبر | 127.0.0.1 فقط |
سجّل، ثم هاجر من رابط يبدو خارجيًا يعيد 302 إلى http://127.0.0.1:.../internal.git. الهجرة المباشرة إلى loopback مرفوضة. أما الاستنساخ الذي يتبع إعادة التوجيه فليس مرفوضًا. فيستقر ملف الإثبات في مستودع الخاص به.
ليس قراءة قرص عبر file://. وليس X-Gitea-Internal-Auth على /api/internal (فـ git لن يضبط ذلك الترويسة). وليس RCE بدون مصادقة. وليس RCE عبر البيانات الوصفية إلا إذا أثبتّ بشكل منفصل أن git خزّن الجسم.
بقايا نفس الوسم: keys IDOR، hostmatcher 0.0.0.0/8.
أغلقت v1.27.3 موجة GHSA لعام 2026: CVE-2026-60004 (RCE عبر خطاف diffpatch، ضمن CISA KEV)، وCVE-2026-59774 (#+INCLUDE في Org-mode بدون مصادقة)، وبوابات Actions لطلبات السحب المتفرعة (fork-PR)، والافتراضي X-WEBAUTH-USER في الوكيل العكسي. ابقَ على 1.27.3+ لأجل تلك. ومع ذلك بقيتُ على ذلك الوسم.
أصلح CVE-2026-59765 دالة Go uri.Open. وأصلح CVE-2026-22874 دالة Go reservedIPNets. أما مُعيد توجيه git فلا يزال FIXME. وسطر سجل التغييرات "disable HTTP redirects on pull mirror sync" لا يخص هذه الدالة.
يضع المختبر Gitea على 8.8.4.2 بحيث يبدو مضيف طُعم على 8.8.4.10 خارجيًا بالنسبة إلى hostmatcher. أما git HTTP الداخلي فيرتبط على loopback فقط داخل netns الخاص بـ Gitea (network_mode: service:gitea، المنفذ 9418). يجب أن تفشل الهجرة المباشرة إلى 127.0.0.1. ويجب أن ينجح الاستنساخ الذي يتبع إعادة التوجيه. يعيد redir.py توجيه 302 من /bait.git إلى http://127.0.0.1:9418/internal.git. ملف الإثبات WITNESS يحتوي على GHSA-GITEA-GIT-REDIR-SSRF.
مسارات خاطئة سُجّلت بالفعل: ALLOW_LOCALNETWORKS true (فتمسح القائمة المسموحة حينها)؛ وfile://؛ وX-Gitea-Internal-Auth؛ وصدفة عكسية (reverse shell). مسرحيات. الضابط هو رفض الهجرة المباشرة إلى loopback.
أخطاء العميل تبدو كأخطاء المنتج. فالمساعد الذي يحجب http.client لا يرسل أي حزمة أصلًا. و.recv() على HTTPResponse ليست .read(). أذكر ذلك مرة واحدة لأنه كلّفني وقتًا، وبدا لدقيقة كأن 1.27.3 قد أنهت المهمة.
cd lab
./run.sh
استهدف فقط http://127.0.0.1:18103. ALLOW_LOCALNETWORKS=false.
negative-loopback status=422 You can not import from disallowed hosts
migrate-bait status=201 clone_addr=http://8.8.4.10/bait.git
fetch raw/WITNESS status=200 GHSA-GITEA-GIT-REDIR-SSRF
SUCCESS Gitea #2 git HTTP redirect SSRF
لا تتعامل مع DNS وقت الإرسال كحدّ فاصل. افرض http.followRedirects=false (وطبّع عناوين URL الخاصة بالاستنساخ إلى .git كي يظل GitLab يعمل)، أو مرّر HTTP الخاص بـ git عبر مُتّصل (dialer) يعيد تشغيل hostmatcher عند كل قفزة.
HandleGitCmdHTTPRedirection · IsMigrateURLAllowedGNU Affero GPL v3.0. راجع LICENSE. للاستخدام في مختبر loopback فقط. دون أي ضمان.