Skip to content
KitploitKITPLOIT
StrumentiExploitsBlog
Log in
Invia
StrumentiExploitsBlog
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.

FeedContattoPrivacy© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
CVE-2026-97332-PoC — PoC indipendente e laboratorio riproducibile per CVE-2026-97332 — divulgazione non autenticata di file privati in User Private Files < 2.2.0 su WordPress Multisite. | Kitploit
Strumenti/GitHubGitHub/kolya080808/cve-2026-97332-poc
Strumenti DifensiviAnalisi delle VulnerabilitàExploitSfruttamento di Applicazioni WebRaccolta InformazioniSicurezza WebPenetration TestingLab e Pratica

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 →
GitHub
kolya080808/cve-2026-97332-poc

CVE-2026-97332-PoC

PoC indipendente e laboratorio riproducibile per CVE-2026-97332 — divulgazione non autenticata di file privati in User Private Files < 2.2.0 su WordPress Multisite.

Vedi RepositorySito web
429 giorni faNon ancora revisionato
Condividi

CVE-2026-97332 — WordPress User Private Files < 2.2.0 Divulgazione non autenticata di file privati (Multisite)

CVE Severity Affected Fixed Requires PoC Ethics

[!NOTE] Questo repository è una riproduzione indipendente e Proof of Concept per CVE-2026-97332.

Scoperta originale della vulnerabilità: Akshat Parikh (SN1PER). CNA / advisory: WPScan. PoC e riproduzione indipendenti: Kolya080808.

Divulgazione non autenticata dei file privati di altri utenti nel plugin WordPress User Private Files (slug wp.org user-private-files) prima della 2.2.0 su installazioni multisite. Il plugin memorizza i documenti privati di ogni utente all'interno del normale albero degli upload e li protegge con una singola RewriteRule aggiunta al .htaccess root, che instrada le richieste dei file attraverso un controllo di accesso PHP. Su una rete multisite quella regola non viene mai raggiunta: una semplice GET — senza cookie, senza header, senza login — restituisce il file privato di un altro utente come contenuto statico. Broken Access Control, CWE-284, CVSS 3.1 5.3 (AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N).

Questo repository contiene un exploit Python funzionante e senza dipendenze e un lab docker a due container (vulnerabile 2.1.9 e corretta 2.2.0, entrambe WordPress multisite) per riprodurre l'attacco end-to-end.

[!CAUTION] Questo materiale è fornito esclusivamente per ricerca di sicurezza autorizzata e test difensivi (vedi il disclaimer in fondo). Attaccare sistemi di cui non si è proprietari o che non si gestiscono senza autorizzazione scritta è illegale.

La vulnerabilità

Il plugin conserva i file privati come normali allegati in una sottodirectory piatta degli upload per sito — wp-content/uploads/upf-docs/ (sito principale) e wp-content/uploads/sites/N/upf-docs/ (sottosito N) — senza alcun isolamento per utente. Il controllo di accesso non è sulla directory; risiede in PHP (dl-file.php: 403 per utenti anonimi, poi un controllo autore/allow-list) ed è raggiunto solo tramite una rewrite emessa all'attivazione del plugin nel .htaccess root:

# appended by 2.1.9 (upvf_actdeact.php), AFTER the WordPress block
RewriteRule ^wp-content/uploads/upf-docs/(.*)$ https://site/?file=$1 [QSA,L]

Su multisite questo non viene mai attivato, per due ragioni indipendenti:

  1. Il file .htaccess della rete intercetta prima i file esistenti. WordPress multisite scrive il proprio set di regole nel file .htaccess radice:

    RewriteCond %{REQUEST_FILENAME} -f [OR]
    RewriteCond %{REQUEST_FILENAME} -d
    RewriteRule ^ - [L]
    

    Una richiesta che corrisponde a un file fisicamente esistente termina la riscrittura proprio lì — Apache lo serve come contenuto statico, e mod_rewrite non raggiunge mai il blocco del plugin alla fine del file. (WordPress a sito singolo usa condizioni negative !-f/!-d, ed è per questo che lo stesso plugin funziona lì.) Questo espone già i file del sito principale della rete.

  2. I percorsi dei sottositi non corrispondono affatto al pattern. Su multisite ogni sito ha i propri upload — wp-content/uploads/sites/N/…, più il prefisso URL /siteN/ nelle reti con sottodirectory — mentre la regola è codificata in modo fisso su ^wp-content/uploads/upf-docs/ dalla base URL del sito principale. Anche dopo che la riscrittura interna della rete rimuove il prefisso /siteN/, il segmento sites/N/ continua a non corrispondere.

Quindi per qualsiasi rete multisite (sia con sottodirectory che con sottodominio) un attaccante non autenticato recupera i file privati direttamente:

GET /wp-content/uploads/upf-docs/victim.pdf HTTP/1.1            (main site)
GET /site2/wp-content/uploads/sites/2/upf-docs/victim.pdf HTTP/1.1  (subsite)

La risposta è 200 con il corpo del file — servito da Apache direttamente da uploads/, il controllo di accesso del plugin non viene mai eseguito.

I nomi dei file sono prevedibili

Nulla nell'URL è segreto. Il plugin costruisce i nomi a partire dall'id utente numerico del proprietario e dai secondi unix del caricamento:

Generatore (2.1.9)Nome su disco
UI moderna, inc/functions-file.php:73-77usr{ID}_{unixtime}_{original}
template classico, inc/classic-user-functions.phpuser_{ID}_doc_{unixtime}.{ext}

Gli id utente su una rete multisito sono piccoli interi sequenziali da una tabella wp_users condivisa, quindi un attaccante necessita solo di un orario di caricamento approssimativo (una finestra di ±2 minuti è ≈240 richieste) e del nome file originale oppure solo della sua estensione. I suffissi di collisione (-1, -2) esistono ma sono rari.

La correzione (2.2.0)

La versione 2.2.0 ha sostituito la riscrittura del file radice con un .htaccess a livello di cartella in upf-docs/ — RewriteRule ^(.*)$ {home}/?file=$1 [R=302,QSA,L], più Require all denied quando mod_rewrite è assente — ricreato a ogni admin_init (auto-riparante, per sottosito). Una regola per-directory scatta per qualsiasi percorso fisico sotto upf-docs/ indipendentemente dal prefisso dell'URL, quindi la GET diretta ora diventa un 302 verso il controllo di accesso e, per gli utenti anonimi, un 403. I file non vengono spostati; cambia solo il meccanismo di intercettazione. Tale distinzione tra 302 e statico è anche ciò che l'exploit usa come rilevatore comportamentale.

Versioni interessate

  • User Private Files < 2.2.0 (verificato sui sorgenti 2.1.9; i tag SVN 1.0.1–2.1.9 presentano lo stesso design di riscrittura radice)
  • Solo installazioni multisito (sottodirectory e sottodominio). Le installazioni a sito singolo sono protette dalla regola radice fintanto che Apache legge .htaccess e il file era scrivibile all'attivazione (nginx richiede la riscrittura manuale del fornitore — vedi il readme del plugin).
  • Riferimento: avviso WPScan d6a144b3-84e3-43eb-92d3-fd4505dd0e1c (pubblicato il 2026-10-02, ricercatore Akshat Parikh / SN1PER).

Come funziona l'exploit

exploit.py usa solo la libreria standard di Python 3 (http.client), non segue redirect e non invia cookie:

  1. Controllo versione (passo 1, prima di qualsiasi attacco): GET /wp-content/plugins/user-private-files/readme.txt, analizza Stable tag:. < 2.2.0 → procedi; >= 2.2.0 → riquadro rosso NOT VULNERABLE - plugin 2.2.0+ (patched) e codice di uscita 6. Se readme.txt non è leggibile, viene mostrata una sonda comportamentale su un nome upf-docs/ inesistente (302 = riscrittura in atto, 404 = consegna statica) e l'esecuzione continua (--skip-check disabilita l'intero passo).
  2. Costruzione URL (passo 2): sito principale {base}/wp-content/uploads/upf-docs/{file} oppure, con --site site2 --site-id 2, {base}/site2/wp-content/uploads/sites/2/upf-docs/{file}.
  3. Recupero (passo 3): una semplice GET, senza Cookie, senza Authorization.
  4. Verdetto (passo 4):
    • 200 → * LEAKED con le prime righe del file come prova, uscita 0;
    • 302 → "redirected to the access check - not vulnerable / patched", uscita 1;
    • 404 → "file not found (wrong name?)" — prova --guess, uscita 1.
Scarica lo strumento