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

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

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

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

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
أدوات/GitHubGitHub/mkway/cve-2026-3304
تحليل الثغرات الأمنيةالاستغلالأمن الويبالتعلم والتعليممختبرات وتدريب عملي
GitHubmkway/cve-2026-3304

CVE-2026-3304

# مختبر إعادة إنتاج لـ CVE-2026-3304، حالة سباق في async fileFilter في Multer تسبب استنزاف القرص عبر ملفات مؤقتة يتيمة. يتضمن خوادم Docker ضعيفة ومصححة، ونصوص استغلال، وتحليل السبب الجذري.

عرض المستودع
21منذ 7 أشهرلم تتم المراجعة بعد

الأكثر شعبية

عرض الكل →

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

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

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

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

بيئة مختبر CVE-2026-3304

لأغراض تعليمية وبحثية فقط. مهاجمة الأنظمة دون إذن أمر غير قانوني.

تم بناء بيئة المختبر هذه من خلال تحليل تصحيح Multer 2.1.0 وكود الاختبار الرسمي الخاص به. الخادم القابل للاستغلال يحاكي الشروط الدقيقة الموضحة في اختبار التصحيح، والخادم المُصحح يعمل بإصدار Multer 2.1.0 للتأكد من أن الإصلاح يعمل.

نظرة عامة على الثغرة

الحقلالتفاصيل
CVECVE-2026-3304
الهدفMulter < 2.1.0 (وسيط multipart/form-data الخاص بـ Node.js)
النوعDoS — ملف يتيم (تنظيف غير مكتمل للملفات المؤقتة)
CWECWE-459: تنظيف غير مكتمل
CVSS 4.08.7 عالية
الإصدار المُصححMulter 2.1.0

طلب multipart مشوّه مع سمة name مفقودة على جزء ملف يتسبب في قيام Multer بإنشاء ملف مؤقت على القرص دون تنظيفه أبدًا. الطلبات المتكررة تستنزف مساحة القرص، مما يؤدي إلى رفض الخدمة (DoS).


تحليل السبب الجذري

تنبع الثغرة من تدفق معالجة استدعاء fileFilter داخل multer/lib/make-middleware.js.

المشكلة الأساسية: توقيت setImmediate + فحص errorOccured المفقود

عندما يقوم Multer ببث وتحليل طلب multipart جزءًا بجزء، يحدث التسلسل التالي:

[تسلسل أحداث التحليل — الإصدار القابل للاستغلال]

1. استلام ترويسة الجزء 1
   → استدعاء fileFilter(req, file, cb)
   → setImmediate(cb) → تأجيل الاستدعاء إلى دورة الحدث التالية

2. استلام جسم الجزء 1
   → فتح /tmp/uploads/<uuid>، وبدء كتابة البيانات

3. استلام ترويسة الجزء 2 (سمة name مفقودة)
   → يكتشف Multer 'name missing'
   → errorOccured = true  ← تعيين علامة الخطأ
   → استدعاء abortWithCode('LIMIT_FIELD_KEY') → جدولة HTTP 500

4. تنفيذ استدعاء setImmediate (دورة الحدث التالية)
   → نتيجة fileFilter: includeFile = true (التدفق الطبيعي)
   → [خطأ] لا يتم فحص علامة errorOccured
   → استدعاء storage._handleFile() → الالتزام بالملف المؤقت على القرص

5. إرسال استجابة HTTP 500
   → يبقى الملف المؤقت على القرص (ملف يتيم)

الكود القابل للاستغلال (make-middleware.js — Multer < 2.1.0)

// استدعاء إكمال fileFilter (مؤجل عبر setImmediate)
fileFilter(req, file, function (err, includeFile) {
  if (err) {
    appender.removePlaceholder(placeholder)
    return abortWithError(uploadedFiles, err)
  }

  if (!includeFile) {
    appender.removePlaceholder(placeholder)
    return fileStream.resume()
  }

  // ❌ لا يتم فحص errorOccured هنا أبدًا
  //    حتى لو تم تعيين خطأ أثناء تحليل الجزء 2، يستمر التنفيذ
  storage._handleFile(req, file, function (err, info) {
    if (err) {
      appender.removePlaceholder(placeholder)
      return abortWithError(uploadedFiles, err)
    }
    // يتم تسجيل الملف المؤقت في uploadedFiles ويُترك على القرص
    appender.replacePlaceholder(placeholder, assign(file, info))
    checkFinished()
  })
})

لماذا يعتبر setImmediate هو المشكلة؟

تغليف fileFilter بـ setImmediate يؤجل استدعاءه إلى دورة الحدث التالية. في هذه النافذة، يستمر busboy (محلل multipart) في تحليل ترويسات الجزء التالي، ويكتشف name المفقود، ويعيّن errorOccured = true. عندما يستأنف الاستدعاء، تكون حالة الخطأ قد تم تعيينها بالفعل — لكن الكود لا يفحصها أبدًا، لذلك يتم استدعاء storage._handleFile دون قيد أو شرط ويتم كتابة الملف المؤقت على القرص.


تحليل كود التصحيح (Multer 2.1.0)

التزام الإصلاح: 739919097d

تمت إضافة حارس if (errorOccured) واحد مباشرة بعد دخول استدعاء fileFilter، قبل الوصول إلى storage._handleFile.

// استدعاء إكمال fileFilter (Multer 2.1.0)
fileFilter(req, file, function (err, includeFile) {
  if (err) {
    appender.removePlaceholder(placeholder)
    return abortWithError(uploadedFiles, err)
  }

  // ✅ [التصحيح] فحص errorOccured قبل المتابعة
  if (errorOccured) {
    appender.removePlaceholder(placeholder)
    return fileStream.resume()   // تصريف التدفق — لا يتم كتابة ملف على القرص
  }

  if (!includeFile) {
    appender.removePlaceholder(placeholder)
    return fileStream.resume()
  }

  storage._handleFile(req, file, function (err, info) {
    if (err) {
      appender.removePlaceholder(placeholder)
      return abortWithError(uploadedFiles, err)
    }
    appender.replacePlaceholder(placeholder, assign(file, info))
    checkFinished()
  })
})

ملخص التغييرات

العنصرقابل للاستغلال (< 2.1.0)مُصحح (2.1.0)
فحص errorOccured❌ غير مُفحص✅ يُفحص فورًا عند دخول الاستدعاء
استدعاء _handleFile عند الخطأنعممحظور
تنظيف الملف المؤقت❌ مفقود✅ عبر fileStream.resume()
الملفات اليتيمة لكل طلب10

لماذا يقوم fileStream.resume() بالتنظيف: استدعاء fileStream.resume() يصرف ويتجاهل التدفق دون تمريره إلى DiskStorage، لذلك لا يتم كتابة أي ملف ولا يبقى شيء على القرص.


كود اختبار التصحيح الرسمي

قام فريق Multer بتضمين اختبار Mocha التالي في تصحيح 2.1.0 للتحقق من الإصلاح. أصبح هذا الاختبار المخطط الأساسي لبيئة المختبر هذه — الخادم القابل للاستغلال يحاكي الإعداد الدقيق الموضح هنا (setImmediate fileFilter + طلب multipart مشوّه)، ويتم التحقق من السلوك المتوقع مقابل كل من الإصدارين القابل للاستغلال والمُصحح.

/* eslint-env mocha */

var assert = require('assert')
var fs = require('fs')
var os = require('os')
var path = require('path')
var http = require('http')

var express = require('express')
var multer = require('../')

describe('async fileFilter cleanup', function () {
  it('does not leave orphan files when request aborts with missing field name', function (done) {
    var uploadDir = fs.mkdtempSync(path.join(os.tmpdir(), 'multer-orphan-'))
    var app = express()

    // Vulnerability trigger: async fileFilter via setImmediate
    var upload = multer({
      dest: uploadDir,
      fileFilter: function (req, file, cb) {
        setImmediate(function () { cb(null, true) })
      }
    })

    app.post('/upload', upload.any(), function (req, res) {
      res.json({ success: true })
    })

    // Error handler: respond with 400
    app.use(function (err, req, res, next) {
      res.status(400).json({ error: err.code })
    })

    var server = app.listen(0, function () {
      var port = server.address().port
      var boundary = 'TestBound'

      // Malicious body: Part 1 valid, Part 2 missing name attribute
      var body =
        '--' + boundary + '\r\n' +
        'Content-Disposition: form-data; name="f"; filename="a.bin"\r\n' +
        'Content-Type: application/octet-stream\r\n\r\nORPHAN FILE DATA\r\n' +
        '--' + boundary + '\r\n' +
        'Content-Disposition: form-data; filename="b.bin"\r\n' +   // ← name= missing
        'Content-Type: application/octet-stream\r\n\r\nx\r\n' +
        '--' + boundary + '--\r\n'

      var req = http.request({
        hostname: 'localhost',
        port: port,
        path: '/upload',
        method: 'POST',
        headers: {
          'Content-Type': 'multipart/form-data; boundary=' + boundary,
          'Content-Length': Buffer.byteLength(body)
        }
      }, function (res) {
        res.resume()
        res.on('end', function () {
          setTimeout(function () {
            var files = fs.readdirSync(uploadDir)

            // Assert 1: server must respond with 400 (error)
            assert.strictEqual(res.statusCode, 400)

            // Assert 2: no orphaned files must remain on disk
            assert.strictEqual(files.length, 0)

            server.close(done)
          }, 500)
        })
      })

      req.write(body)
      req.end()
    })
  })
})
التأكيدالمعنى
res.statusCode === 400يرفض Multer الطلب المشوّه بشكل صحيح
files.length === 0لا توجد ملفات يتيمة متبقية على القرص (تم التحقق من التصحيح)

على إصدار قابل للاستغلال (< 2.1.0)، تكون قيمة files.length مساوية لـ 1 ويفشل التأكيد.


تنفيذ المختبر

يعكس هذا المختبر مباشرة إعداد اختبار التصحيح أعلاه.

الخادم القابل للاستغلال (Dockerfile + app/server.js) يعمل بإصدار Multer 2.0.2 مع fileFilter غير متزامن باستخدام setImmediate — شرط التشغيل الدقيق من اختبار التصحيح:

تنزيل الأداة