Skip to content
KitploitKITPLOIT
ツールエクスプロイトブログ
Log in
提出
ツールエクスプロイトブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

フィードお問い合わせプライバシー© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2026-3304 — # CVE-2026-3304 再現ラボ Multerのasync fileFilterにおける競合状態を再現するラボです。孤立した一時ファイルを介してディスク枯渇を引き起こします。脆弱なDockerサーバーとパッチ適用済みDockerサーバー、エクスプロイトスクリプト、根本原因分析が含まれています。 | Kitploit
ツール/GitHubGitHub/mkway/cve-2026-3304
脆弱性分析エクスプロイトウェブセキュリティ学習と教育ラボと実践
GitHubmkway/cve-2026-3304

CVE-2026-3304

# CVE-2026-3304 再現ラボ Multerのasync fileFilterにおける競合状態を再現するラボです。孤立した一時ファイルを介してディスク枯渇を引き起こします。脆弱なDockerサーバーとパッチ適用済みDockerサーバー、エクスプロイトスクリプト、根本原因分析が含まれています。

リポジトリを見る
217ヶ月前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

CVE-2026-3304 ラボ環境

教育および研究目的のみに使用してください。許可なくシステムを攻撃することは違法です。

このラボ環境は、Multer 2.1.0 のパッチとその公式テストコードを分析して構築されました。 脆弱なサーバーはパッチテストに記載された正確な条件を再現しており、 パッチ適用済みサーバーは Multer 2.1.0 を実行して修正が機能することを確認します。

脆弱性の概要

フィールド詳細
CVECVE-2026-3304
対象Multer < 2.1.0(Node.js multipart/form-data ミドルウェア)
タイプDoS — 孤立ファイル(不完全な一時ファイルのクリーンアップ)
CWECWE-459: 不完全なクリーンアップ
CVSS 4.08.7 HIGH
パッチ適用バージョンMulter 2.1.0

ファイルパートに name 属性が欠落した不正な multipart リクエストにより、Multer はディスク上に一時ファイルを作成しますが、それをクリーンアップしません。リクエストを繰り返すとディスク容量が枯渇し、サービス拒否(DoS)が発生します。


根本原因の分析

この脆弱性は、multer/lib/make-middleware.js 内の fileFilter コールバック処理フローに起因します。

核心的な問題: 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

fileFilter コールバックのエントリ直後、storage._handleFile に到達する前に、 単一の if (errorOccured) ガードが追加されました。

// 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 チームは、修正を検証するために 2.1.0 パッチに以下の Mocha テストを含めました。 このテストはこのラボ環境の設計図となりました — 脆弱なサーバーは ここに記載された正確なセットアップ(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 === 400Multer が不正なリクエストを正しく拒否する
files.length === 0ディスク上に孤立ファイルが残らない(パッチ検証済み)

脆弱なバージョン(< 2.1.0)では、files.length は 1 となり、アサーションは失敗します。


ラボ実装

このラボは、上記のパッチテストのセットアップを直接ミラーリングしています。

脆弱なサーバー(Dockerfile + app/server.js)は、setImmediate を使用した非同期 fileFilter で Multer 2.0.2 を実行します — パッチテストの正確なトリガー条件です:

// app/server.js — パッチテストの脆弱性トリガーを再現
const upload = multer({
  dest: UPLOAD_DIR,
  fileFilter: function (req, file, cb) {
    setImmediate(function () {   // ← コールバックを延期し、競合状態を作り出す
      cb(null, true)
    })
  }
})

パッチ適用済みサーバー(Dockerfile.patched)は同じ server.js を実行しますが、Multer 2.1.0 をインストールします。 ここでは errorOccured ガードが有効であり、パッチテストの期待される合格状態に一致します。

サーバーポートMulter期待される動作
脆弱なバージョン30002.0.2不正なリクエストごとに孤立ファイルが作成される
パッチ適用済み30012.1.0孤立ファイルなし — クリーンアップが正しく機能する

注記: fileFilter を同期に切り替える(setImmediate を削除する)と、Multer < 2.1.0 でも孤立ファイルの発生を防げます。 この脆弱性には両方の条件が必要です: 非同期の fileFilter および errorOccured チェックの欠如。


攻撃: 不正な POST リクエスト

この攻撃は、2番目のパートに必須の name 属性が欠落した multipart/form-data POST を送信します。

正常なリクエスト(安全)

POST /upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----Boundary

------Boundary
Content-Disposition: form-data; name="file"; filename="photo.jpg"
Content-Type: application/octet-stream

<binary data>
------Boundary--
ツールをダウンロード