Skip to content
KitploitKITPLOIT
أدواتالمدونة
Log in
إرسال
أدواتالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

الخلاصاتاتصالالخصوصية© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
gortex-PoC — PoC — تتبع الروابط الرمزية للكشف عن محتوى خارج المستودع عبر search_text في Gortex (GHSA-6vhf-4wcm-2r83, CVE-2026-87003, CVSS 5.5). | Kitploit
أدوات/GitHubGitHub/squeeze440/gortex-poc
التحليل الثابتتحليل الثغرات الأمنيةتحليل الكودالاستغلالجمع المعلوماتأمن الويبالأوراق والأبحاث
GitHubsqueeze440/gortex-poc

gortex-PoC

PoC — تتبع الروابط الرمزية للكشف عن محتوى خارج المستودع عبر search_text في Gortex (GHSA-6vhf-4wcm-2r83, CVE-2026-87003, CVSS 5.5).

عرض المستودع
27منذ 19 أياملم تتم المراجعة بعد

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة

متابعة الروابط الرمزية في مسار ملفات المفهرس → الكشف عن محتوى خارج المستودع عبر search_text

حالة CVE: مطلوبة، بانتظار الإسناد. تم نشر هذا الاكتشاف باسم GHSA-6vhf-4wcm-2r83. عند إسناد CVE يُعاد تسمية هذا المستودع CVE-YYYY-NNNNN-gortex-PoC وتُستبدل هذه اللافتة برابط CVE.

الباحثDostxodjayev Abdullox (@squeeze440)
الاستشارةGHSA-6vhf-4wcm-2r83
CVSS 3.15.5 (متوسط)
الضعفCWE-59, CWE-200

متابعة الروابط الرمزية في مسار ملفات المفهرس → الكشف عن محتوى خارج المستودع عبر search_text

الملخص

يسمح خلل في حل الروابط (CWE-59) في مفهرس المستودعات الخاص بـ gortex بمرور مدخلة ملف مرتبطة رمزياً تشير إلى خارج جذر المستودع المفهرس بصمت، وفهرسة محتواها، ثم تقديمه لاحقاً كما هو — بما في ذلك إلى هدف خارج الجذر بالكامل — عبر مصرف إعادة القراءة الحية لأداة MCP المسماة search_text، والتي لا تطبّق أبداً فحص الحجز guardSymlinkWithinRepo الخاص بالمشروع نفسه.

المنتج

zzet/gortex — https://github.com/zzet/gortex

الإصدار المُختبَر

الالتزام b5a63e25c0719c8ce935e59abf85618e2b4b1e64 (git describe: v0.62.0-35-gb5a63e25)، وهو HEAD المستودع وقت التدقيق. تأكد أنه لا يزال موجوداً في أحدث إصدار موسوم v0.62.0، أي بعد أن استقر إصلاح الاستشارة غير ذات الصلة GHSA-w42c-h7hr-f67p (v0.55.0).

تقدير CVSS v3.1

CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N — 5.5 (متوسط)

  • AV:L — يتوافق مع سابقة التقييم الخاصة بهذا المشروع لواجهة MCP الخاصة به (GHSA-w42c-h7hr-f67p استخدم أيضاً AV:L): النشر الافتراضي هو خادم MCP محلي يُوصَل إليه عبر stdio بواسطة عملية الوكيل على نفس المضيف؛ AV:N لا ينطبق إلا على وضع --http-addr الاختياري.
  • UI:R — يتطلب أن يصدر عميل MCP (وكيل LLM، أو إنسان عبر gortex call) استدعاء search_text / search_text regexp:true. يكفي نص حرفي واسع (مثل حرف شائع واحد) أو تعبير نمطي مطابق (.) مقابل مستودع مفهرس يحتوي على الرابط الرمزي المزروع لإفراغ الملف الهدف — دون الحاجة إلى معرفة سرية بمحتواه — لذا فهذا عتبة منخفضة، لكنه إجراء متميز عن مجرد الفهرسة.
  • C:H — الكشف عن محتوى ملفات عشوائية، بلا حدود تحددها حدود المستودع، لأي شيء يستطيع مستخدم نظام التشغيل الخاص بالخادم قراءته (مفاتيح SSH، ملفات بيانات الاعتماد السحابية، مستودعات مستأجرين آخرين في خادم متعدد المستودعات، إلخ)، يُعاد كما هو في استجابة الأداة.
  • I:N / A:N — هذا خلل في مسار القراءة فقط؛ لا يُكتب شيء ولا يُجعل شيء غير متاح.

التفاصيل

السبب الجذري 1 — مسار المفهرس لا يفحص أبداً مدخلات الملفات المرتبطة رمزياً

internal/indexer/indexer.go:2549-2604، مسار قبول المجموعة الأساسي:

err = filepath.WalkDir(absRoot, func(path string, d os.DirEntry, err error) error {
    if err != nil { return nil }
    if d.IsDir() {
        if idx.shouldPruneDir(path, absRoot) { return filepath.SkipDir }
        return nil
    }
    lang, ok := idx.effectiveLanguage(path, nil)   // detects by extension; symlink name is enough
    if !ok { return nil }
    if idx.shouldExclude(path, absRoot, false) { return nil }
    info, statErr := d.Info()                      // Lstat'd DirEntry.Info() — no ModeSymlink check
    ...
    files = append(files, walkedFile{path: path, lang: lang, size: info.Size(), mtimeNano: info.ModTime().UnixNano()})
    return nil
})

يستخدم filepath.WalkDir دلالات Lstat، لذا فإن المجلد المرتبط رمزياً محمي بطبيعته — d.IsDir() تكون false له ولا يُتكرر الدخول إليه أبداً. أما مدخلة الملف المرتبط رمزياً فلا تحصل على حماية مكافئة: لا شيء هنا (ولا في shouldExclude/shouldPruneDir، internal/indexer/indexer.go:5724-5813، التي تطابق فقط أنماط مسارات بنمط gitignore) يستدعي d.Type()&os.ModeSymlink أو os.Lstat أو filepath.EvalSymlinks على مدخلة الملف قبل إدراجها في قائمة الانتظار. ملف باسم مثل pwn.go هدفه /etc/passwd أو ~/.ssh/id_rsa أو مستودع مستأجر آخر يُقبل لمجرد أن اسمه يطابق امتداداً مسجلاً (effectiveLanguage، internal/parser DetectLanguageContent، قائم على المسار). قائمة الملفات الممرورة هذه بالضبط تصبح idx.fileMtimes (internal/indexer/indexer.go:3760: idx.fileMtimes[idx.relKey(f.path)] = f.mtimeNano).

السبب الجذري 2 — مصرف search_text يعيد قراءة الملفات الحية دون حارس حجز

internal/indexer/grep.go:17-64 (GrepText / warmTrigramSearcher) يبني باحث الـ trigram مباشرة من مفاتيح idx.fileMtimes:

rels := ... // from idx.fileMtimes, i.e. includes the symlinked file's rel path
idx.trigramSearcher = trigram.Build(root, rels)

ثم يقوم internal/search/trigram/searcher.go:32-48 (Build) و:55-86/:102-176 (Grep/GrepRegexp) بما يلي:

content, err := os.ReadFile(filepath.Join(root, filepath.FromSlash(rel)))  // Build — follows symlink
...
f, err := os.Open(filepath.Join(s.root, filepath.FromSlash(rel)))          // Grep/GrepRegexp — follows symlink

يتبع os.ReadFile/os.Open الروابط الرمزية افتراضياً (بدون O_NOFOLLOW). لا هذه الدالة ولا internal/mcp/tools_search_text.go:35-126 (handleSearchText، معالج MCP الذي يستدعي s.indexer.GrepText/GrepRegexp) يستدعي أبداً resolveFilePath أو guardSymlinkWithinRepo. هاتان دالتا الحجز موجودتان وموصولتان بشكل صحيح في كل مسار آخر يقدّم المحتوى — internal/mcp/tools_fileops.go (read_file، write_file/edit_file اعتباراً من إصلاح v0.55.0)، internal/mcp/tools_coding.go:919 (get_symbol_source)، internal/mcp/tools_lsp.go:264، internal/mcp/tools_export.go:95 — لكن مسار grep بالـ trigram في search_text مصرف منفصل لم يُمنح نفس الحارس أبداً. يؤكد grep -rn guardSymlinkWithinRepo عبر الشجرة عدم وجود أي إشارات في tools_search_text.go أو grep.go أو trigram/searcher.go.

فحص خطر التكرار / التميز

هذا متميز حقاً عن GHSA-w42c-h7hr-f67p:

  • تلك الاستشارة: مسار الكتابة، resolveFilePath يعفي المسارات المطلقة + write_file/edit_file/move_inline لا تستدعي أبداً guardSymlinkWithinRepo (أُصلح في v0.55.0).
  • هذا الاكتشاف: مسار القراءة، مسار الاكتشاف الخاص بالمفهرس نفسه (وليس أي معالج MCP) يقبل ملفاً مرتبطاً رمزياً دون فحص Lstat، وأداة MCP مختلفة (search_text، وليس read_file/get_symbol_source) تقدّم محتواه عبر مصرف (internal/search/trigram) لا يستدعي بشكل مستقل أبداً guardSymlinkWithinRepo. لم يمس إصلاح مسار الكتابة أي من هذين الموقعين. هذا يطابق نمط الأدوات الشقيقة المؤكد بالفعل في ozgurcd/gograph (GHSA-6h6w-vhgr-2hp6) وvitali87/code-graph-rag (GHSA-85gg-2gfq-q95m): مسار اكتشاف ملفات دون حماية من الروابط الرمزية، مقترن بمصرف يقدّم المحتوى يفتقر بشكل مستقل إلى حارس حجز.

إثبات المفهوم

التتبع الساكن (مراجع file:line أعلاه) كامل وقابل لإعادة الإنتاج بالفحص. تمت محاولة التحقق الديناميكي وهو محجوب فعلاً بفجوة في سلسلة الأدوات في هذه البيئة المعزولة، موثّق بأمانة بدلاً من التغطية عليه:

$ CGO_ENABLED=1 go test ./internal/mcp/... -run TestPoC_SymlinkFollow_SearchTextDisclosesOutOfRepoContent -v
mcp [build failed]
  cgo: C compiler "gcc" not found: exec: "gcc": executable file not found in $PATH

كل مستخرج لغة tree-sitter في قاعدة الشيفرة هذه (بما في ذلك مستخرج Go العادي، github.com/tree-sitter/tree-sitter-go's bindings/go/binding.go: // #cgo CFLAGS: -std=c11 -fPIC / import "C") يتطلب cgo للترجمة — لا يوجد مسار شيفرة Go خالص لتسجيل لغة واحدة حتى، لذا لا يمكن بناء parser.Registry دون مترجم C عامل. لا تحتوي هذه البيئة المعزولة على gcc/cc/clang في $PATH ولا صلاحية root بدون كلمة مرور (sudo -l يطلب كلمة مرور تفاعلية) لتثبيت أحدها عبر apt-get install gcc (موجود في ذاكرة apt المؤقتة، gcc-16/kali-last-snapshot، لكنه غير قابل للوصول دون صلاحية). هذا قيد بيئي، وليس اكتشافاً عن gortex.

اختبار PoC نفسه — المكتوب وفق نمط أداة الاختبار الموجودة في المشروع نفسه (internal/mcp/tools_search_text_test.go's TestSearchText، ونفس شكل newSingleRepoServer/callTool الذي استخدمته PoC الاستشارة السابقة) — متروك في مكانه عند internal/mcp/poc_symlink_search_disclosure_test.go ليُشغّله المشرف في بيئة تحتوي على سلسلة أدوات C:

تنزيل الأداة