
Questo è uno scanner CVE-2025-29927.
Questo è uno scanner di livello professionale progettato per rilevare la vulnerabilità di bypass del middleware CVE-2025-29927 nelle applicazioni Next.js.
X-Middleware-Subrequest appositamente costruiti per bypassare il middleware di Next.jspip install -r requirements.txt playwright install
### Esegui lo scanner```bash
python main.py --domain https://example.com --threads 10 --timeout 10 --save
python main.py --help
| Option | Description |
|----------------|--------------------------------------------|
| `--domain` | URL base del sito di destinazione (obbligatorio) |
| `--user-agent` | User-agent personalizzato (predefinito: stringa Chrome) |
| `--timeout` | Timeout della richiesta (predefinito: 10 secondi) |
| `--proxy` | Indirizzo proxy (facoltativo) |
| `--save` | Salva i risultati in `results.txt` |
| `--threads` | Numero di thread (predefinito: 10) |
| `--wordlist` | Wordlist include percorsi comuni |
---
## 🐳 Utilizzo Docker
### Crea l'immagine Docker```bash
docker build -t cve-scanner .
docker run -it --rm cve-scanner --domain https://example.com --save
---
## ⚙️ GitHub Actions
Questo progetto include un workflow di GitHub Actions per testare la configurazione al push. Esso:
- Installa le dipendenze
- Installa i browser di Playwright
- Esegue un controllo `--help`
Vedi `.github/workflows/python.yml`.
---
## 🧱 Struttura```
.
├── main.py # Entry point
├── config.py # CLI parser
├── crawler.py # Playwright crawler
├── scanner.py # Multi-threaded vulnerability testing
├── requirements.txt
├── Dockerfile
└── .github/workflows
Panoramica della vulnerabilità CVE-2025-29927
CVE-2025-29927 è una grave falla di sicurezza di Next.js che consente agli attaccanti di bypassare l'autenticazione e l'autorizzazione basate su middleware. Includendo uno speciale header interno (X-Middleware-Subrequest) nelle richieste HTTP, un attaccante può ingannare il server Next.js facendogli saltare l'esecuzione del middleware, ottenendo così accesso a rotte protette. In pratica, una richiesta che normalmente sarebbe bloccata dal middleware di autenticazione (ad esempio restituendo un 401/403 o reindirizzando al login) viene elaborata normalmente se questo header è presente, bypassando di fatto i controlli di sicurezza. La vulnerabilità riguarda le versioni di Next.js dalla 11.1.4 alla 15.2.2, e gli amministratori sono invitati ad applicare patch o implementare mitigazioni (come rimuovere questo header a livello di proxy) per proteggere le proprie applicazioni.
Individuare questa vulnerabilità in un'applicazione web richiede di scoprire gli endpoint interni e testarli con l'header dannoso per verificare se è possibile un accesso non autorizzato. Di seguito viene presentato un piano di progettazione per uno script Python avanzato che esegue il crawling di un sito web target (con pieno supporto JavaScript) e cerca CVE-2025-29927, soddisfacendo tutti i requisiti specificati.
Per soddisfare il requisito di un crawling approfondito che includa contenuti renderizzati da JavaScript, utilizzeremo Playwright (preferito a Selenium per velocità e API moderna). Playwright è una potente libreria di automazione di browser headless in grado di gestire applicazioni web dinamiche e moderni framework JS. Rispetto a Selenium, Playwright offre un'API più moderna (basata su Chrome DevTools Protocol) e supporta sia l'operazione sincrona che asincrona, il che può garantire prestazioni migliori per il nostro caso d'uso. Le librerie chiave e le relative istruzioni di installazione includono:
playwright – per l'automazione di browser headless (per caricare SPA o pagine che richiedono JavaScript). (Installazione: pip install playwright ed eseguire playwright install per ottenere i binari del browser).
requests o httpx – per inviare richieste HTTP durante la fase di scansione. Possiamo usare requests per semplicità oppure httpx/aiohttp per il supporto asincrono. (Installazione: pip install requests oppure pip install httpx).
bs4 (BeautifulSoup) – per analizzare l'HTML ed estrarre i link quando necessario. Playwright può interrogare direttamente il DOM, ma usare BeautifulSoup sul contenuto HTML della pagina è semplice per trovare i tag anchor. (Installazione: pip install beautifulsoup4).
concurrent.futures (built-in) o asyncio – per implementare la concorrenza. Per il multi-threading, verrà usato concurrent.futures.ThreadPoolExecutor di Python (nessuna installazione aggiuntiva). Se si utilizza un approccio asincrono, si possono usare asyncio con per richieste parallele.
Motivazione: Playwright è stato scelto per la sua capacità di estrarre contenuti dinamici senza eccessive complessità. «Con Playwright possiamo automatizzare browser headless... per navigare sul web proprio come farebbe un essere umano, il che lo rende ideale per lo scraping di siti web dinamici basati su JavaScript». Questo garantisce che il nostro crawler possa vedere link o elementi UI generati dagli script (che un semplice crawler basato su requests non vedrebbe).
Il modulo crawler userà Playwright in modalità headless per eseguire un crawling approfondito del sito target. L'obiettivo è scoprire i percorsi interni (endpoint) da testare, inclusi quelli visibili solo dopo l'esecuzione di JavaScript. Punti chiave di progettazione del crawler:
Navigazione con browser headless: Avviare un'istanza del browser (ad es. Chromium) in modalità headless tramite Playwright. Usare un Browser Context con un User-Agent personalizzato se specificato dall'utente (maggiori dettagli nella prossima sezione). Ad esempio, possiamo creare un context con browser.new_context(user_agent=<user_agent_string>) per emulare lo User-Agent scelto. Se è configurato un proxy, applicarlo all'avvio (Playwright consente di impostare un server proxy quando si avvia il browser o il context).
Strategia di crawling ricorsivo: Partire da un URL di base (seed). Usare page.goto(base_url, timeout=<T>) per caricare la pagina (timeout configurabile). Attendere che la rete sia inattiva o un breve intervallo per consentire il caricamento dei contenuti dinamici, se necessario. Poi estrarre i link. Possiamo estrarre i link in due modi:
Eseguire JavaScript nel contesto della pagina per raccogliere tutti gli anchor, ad es. links = page.evaluate("Array.from(document.querySelectorAll('a[href]'), a => a.href)"), oppure
Recuperare l'HTML della pagina (content = page.content()) e usare BeautifulSoup per analizzarlo e trovare tutti gli attributi <a href>.
Filtraggio dei link: Filtrare i link che non appartengono al dominio target (per restare su risorse interne). Inoltre, ignorare gli URL di file statici come immagini, CSS, JS, ecc. Ad esempio, saltare qualsiasi URL con estensioni di file come .css, .js, .jpg, .png, .gif, .svg, .woff ecc. Un approccio pratico (ispirato al template di ProjectDiscovery) è ignorare qualsiasi percorso che contenga un "punto" dopo la prima barra. Hanno estratto gli endpoint con un pattern regex href=['"](https://github.com/houmanpashaei/cve-2025-29927/blob/HEAD/%5C/.%5B%5E.%5C%22%27%5D+)['"] – che cattura i percorsi interni senza punto (saltando quindi le risorse statiche). Implementeremo una logica simile nel codice per evitare di accodare risorse statiche o link esterni.
Tracciamento e controllo della profondità: Mantenere un insieme di URL visitati per evitare loop infiniti o ripetizioni. Usare una coda (FIFO) per l'attraversamento BFS del grafo dei link del sito. Opzionalmente, consentire all'utente di specificare un limite di profondità di crawl o un numero massimo di pagine da visitare, per evitare di girare all'infinito su siti di grandi dimensioni.
Contenuti renderizzati da JavaScript: Poiché usiamo un browser reale, anche i link aggiunti al DOM dagli script (ad esempio, un'app React che renderizza un menu dopo aver recuperato i dati) saranno visibili al nostro crawler. Dovremmo valutare la possibilità di cliccare o interagire se necessario (ad esempio, se alcune pagine si caricano solo dopo un'azione dell'utente). Tuttavia, per mantenere le cose semplici e veloci, il progetto iniziale si concentrerà sulla raccolta degli href degli <a> in ogni pagina caricata. Potremo migliorarlo in seguito per gestire elementi come lo scroll infinito o contenuti dietro clic, se l'applicazione target lo richiede.
Efficienza: Playwright supporta l'esecuzione di più pagine/schede in parallelo tramite la sua API asincrona. Potremmo istanziare più pagine con asyncio.gather per recuperare più link in concorrenza. Per un'implementazione iniziale, un approccio più semplice è eseguire il crawling in sequenza (più facile da implementare) e affidarsi alla scansione multi-thread per le prestazioni. Se necessario, un'ottimizzazione avanzata potrebbe coinvolgere un crawl asincrono (usando async with async_playwright() e attendendo più chiamate page.goto). Ma poiché l'automazione del browser è più pesante in termini di risorse, un approccio prudente è mantenere una o poche pagine del browser alla volta per non sovraccaricare il sistema.
All'avvio, lo script presenterà un menu di configurazione intuitivo, consentendo all'utente di personalizzare i parametri di scansione o accettare i valori predefiniti. Questo può essere fatto tramite un menu interattivo nella console (usando i prompt input()) o tramite argomenti della riga di comando (usando argparse per un'esperienza CLI più professionale). Le opzioni includono:
User-Agent personalizzato: L'utente può specificare una stringa User-Agent personalizzata da usare per crawler e scanner. Verrà applicata al context del browser Playwright e a qualsiasi richiesta HTTP diretta. Usare uno User-Agent non predefinito può aiutare a evitare il rilevamento banale dei bot. (Di default, Playwright potrebbe usare qualcosa di identificabile; possiamo sovrascriverlo facilmente come mostrato sopra.) Ad esempio, l'utente può inserire una stringa che identifica Chrome su Windows, che passiamo alla creazione del context di Playwright.
Timeout delle richieste: L'utente può impostare un timeout (in secondi) per il caricamento delle pagine e per le richieste HTTP. Questo evita che lo scanner rimanga bloccato troppo a lungo su endpoint che non rispondono. Applicheremo questa impostazione in page.goto(timeout=...) per il crawling e nelle richieste (ad es., requests.get(timeout=...)) per la scansione.
Impostazioni proxy: Se l'utente vuole instradare il traffico attraverso un proxy (per anonimato o per raggiungere host interni), può inserire l'URL del proxy (e le credenziali se necessarie). Lo script configurerà il browser Playwright per usare questo proxy all'avvio (ad es., browser.launch(proxy={"server": "http://<proxy_host>:<port>", "username": "...", "password": "..."}) come mostrato negli esempi). Allo stesso modo, per le richieste imposteremo il parametro proxies (o le variabili d'ambiente) di conseguenza.
Output su file: Il menu chiederà se l'utente desidera salvare i risultati in un file (ad es., results.txt). In caso affermativo, lo script scriverà su questo file tutti gli endpoint vulnerabili scoperti e i relativi dettagli, oltre a stamparli a schermo. In caso contrario, i risultati verranno solo stampati su stdout. (Potremmo comunque registrare tutti i percorsi scansionati in un log verbose se necessario, ma il file registrerà specificamente i positivi o un report completo in base alle preferenze dell'utente.)
Altre opzioni: Possiamo includere interruttori come "Modalità verbose" per il logging di debug, o "Profondità/pagine massime di crawl" se necessario. Queste aiutano l'utente a ottimizzare la scansione. Per l'ambito iniziale, le quattro opzioni principali sopra elencate sono sufficienti.
Il sistema di menu sarà implementato in un modulo di configurazione/setup dedicato. Potrebbe essere semplicemente una funzione che stampa i prompt e raccoglie l'input, con valori predefiniti sensati se l'utente preme Invio (ad es., user-agent predefinito standard, timeout predefinito = 10 secondi, nessun proxy, nessun file di output). Questo mantiene chiara l'interazione e consente allo script di funzionare anche in modalità non interattiva (se in seguito aggiungeremo argomenti da riga di comando, potremo bypassare i prompt interattivi fornendo tutta la configurazione necessaria tramite args).
Le prestazioni sono cruciali per uno scanner, soprattutto se vengono trovati molti endpoint. Lo script utilizzerà la concorrenza per la velocità, tramite multi-threading o asyncio (o una combinazione):
Scansione multi-thread: Poiché la scansione dei percorsi scoperti (invio di richieste HTTP con header) è un'attività legata all'I/O, possiamo usare tranquillamente i thread Python per parallelizzarla. Le operazioni di I/O rilasciano il Global Interpreter Lock, consentendo a più thread di avanzare contemporaneamente sulle richieste di rete. Con concurrent.futures.ThreadPoolExecutor, possiamo avere un pool di thread di lavoro che gestiscono ciascuno un sottoinsieme dei compiti di scansione. Questo può accelerare notevolmente il processo: ad esempio, eseguire 5 thread in parallelo potrebbe ridurre il tempo di scansione di circa 5 volte, come dimostrato in altri contesti di web scraping. Permetteremo di configurare il numero di thread oppure sceglieremo un valore predefinito sensato (ad esempio 10 thread) bilanciando velocità e carico sul server. Ogni thread prende URL da una coda condivisa di endpoint da testare.
Alternativa asyncio: In alternativa, si può usare un approccio asincrono, soprattutto se si utilizza Playwright in modalità async o httpx per le richieste HTTP. Potremmo await più richieste simultaneamente. Ad esempio, httpx.AsyncClient può inviare molte richieste in concorrenza e raccogliere i risultati. Questo approccio evita l'overhead dei thread e può essere molto efficiente per un grande numero di endpoint. Tuttavia, mescolare asyncio con Playwright (che a sua volta può essere usato in modo asincrono) potrebbe complicare le cose. Una soluzione pragmatica è usare il threading per la fase di scansione HTTP (poiché il crawling con Playwright potrebbe essere più facile da gestire in modalità sincrona).
Crawling concorrente: Dovremmo anche considerare di parallelizzare il crawl se il sito è grande. Playwright può aprire più pagine contemporaneamente usando un context asincrono. Potremmo implementare una concorrenza limitata (ad es., 2-3 pagine alla volta) per il crawling. Ad esempio, man mano che estraiamo nuovi URL, potremmo avviare una nuova Page per ciascuno se usiamo asyncio. Questa può essere un'ottimizzazione avanzata se necessaria. Inizialmente, un crawl a thread singolo è più semplice e adatto a siti di dimensioni moderate, ma il design può segnalarlo come punto di miglioramento.
In sintesi, la concorrenza verrà applicata principalmente alla fase di scansione per testare più endpoint in parallelo. Questo rende lo scanner molto più veloce senza sacrificare troppo l'accuratezza (poiché ogni richiesta è indipendente). Come osserva un riferimento: «Il multithreading con concurrent.futures può dare un notevole impulso qui. Possiamo eseguire attività di I/O in modo concorrente su più thread e vedere un grande aumento di velocità». Il multi-threading è adatto in questo caso perché le attività legate alla rete ne traggono beneficio anche in Python.
Il cuore dello script è il modulo di scansione, che prende l'elenco degli endpoint scoperti (percorsi) e controlla ciascuno per individuare segni della vulnerabilità CVE-2025-29927. Il processo per ogni endpoint sarà:
x-middleware-rewrite, x-middleware-next o x-middleware-redirect, ciò suggerisce che questa rotta è protetta da middleware. Controlliamo anche se lo stato non è 200 (il che significa che l'accesso è stato negato o reindirizzato), poiché sono quelli che probabilmente possono essere bypassati. (Se lo stato è già 200 e il contenuto si carica normalmente, o è una pagina pubblica o la vulnerabilità non si applica; potremmo comunque testarla, ma il vero interesse sono le pagine protette.)X-Middleware-Subrequest. Proveremo una varietà di valori per l'header per garantire il rilevamento nelle diverse versioni di Next.js:Un valore generico come "1" o "true" (alcune fonti suggeriscono che impostare semplicemente l'header a qualsiasi valore attivi il salto del middleware).
Il payload specifico usato negli exploit pubblici, ad es. "middleware:middleware:middleware:middleware:middleware" (cinque ripetizioni di "middleware"). È noto che induca il bypass per le versioni più recenti (13+). Includeremo esattamente questo valore.
L'output dello script dovrebbe essere facile da leggere e interpretare, oltre a poter essere opzionalmente salvato su file. Formatteremo l'output della console con intestazioni chiare e indentazione dove appropriato. Alcune considerazioni:
Dopo la scansione, stampa un riepilogo dei risultati. Ad esempio: “Scan Complete: 3 vulnerable endpoints found (out of 45 tested).” Poi elenca gli endpoint vulnerabili con i dettagli.
Usa un formato coerente per ogni riga di risultato, come mostrato sopra, possibilmente con tag [VULNERABLE] per attirare l'attenzione. Se si usa una libreria come rich, potremmo persino colorare "VULNERABLE" in rosso o giallo. Anche senza librerie aggiuntive, possiamo usare i codici ANSI tramite colorama per evidenziare, o semplicemente testo maiuscolo.
Se non vengono trovate vulnerabilità, dillo esplicitamente: "No vulnerabilities detected for CVE-2025-29927."
Se i risultati devono essere salvati, assicurati che vengano scritti nel file con un formato simile. Possibilmente in modo leggermente più dettagliato o in CSV per l'uso programmatico, ma poiché l'utente ha menzionato specificamente un file di testo, probabilmente scriveremo semplicemente le stesse righe in results.txt.
Inoltre, eventuali errori critici o eccezioni incontrati (come l'impossibilità di caricare una determinata pagina) possono essere riportati nell'output in modo elegante (invece di uno stack trace). Possiamo catturare le eccezioni e stampare un avviso di una riga per ogni URL fallito: ad es., "Timeout loading /blog (skipped)". In questo modo, l'utente sa se alcuni percorsi non sono stati testati.
Durante l'esecuzione, potremmo mostrare uno spinner o un indicatore di avanzamento (per esecuzioni lunghe) o almeno stampare quale pagina viene crawlerizzata o quale endpoint viene testato, se la modalità verbose è attiva. Per un output più pulito, potremmo mostrare solo i casi vulnerabili scoperti alla fine, ma un log in tempo reale (magari scritto su un file di log separato) può aiutare la trasparenza.
Data l'enfasi su un formato chiaro, usare elenchi puntati o una disposizione a tabella potrebbe aiutare quando si stampano più risultati:
Potremmo tabulare come: Endpoint | Base Status | Base Length | Bypass Status | Bypass Length | HeaderValueUsed | Result
Tuttavia, una semplice forma a frase potrebbe essere più leggibile per un'ampia gamma di utenti. Assicureremo che ogni risultato sia su una nuova riga ed etichettato chiaramente.
Fornendo sia l'output a schermo sia un salvataggio su file opzionale, lo strumento è utile sia per l'uso interattivo sia per la scansione automatizzata (dove l'utente può successivamente rivedere il file o integrarlo nei report).
Per rendere lo script manutenibile e di livello professionale, organizzeremo il codice in moduli, ciascuno dei quali gestisce un aspetto distinto della funzionalità. Una possibile struttura del progetto:
crawler.py: Contiene la logica di crawling tramite Playwright. Avrà funzioni come crawl_site(start_url, config) -> List[str] che restituisce un elenco di percorsi interni scoperti. Questo modulo gestirà l'avvio del browser, il recupero delle pagine, l'estrazione dei link e l'applicazione dei filtri (dominio, esclusione dei file statici). Potrebbe anche ospitare la logica helper per normalizzare gli URL (ad es., rimuovere i frammenti di URL, gestire i percorsi relativi tramite urllib.parse.urljoin).
scanner.py: Contiene la logica di scansione per la vulnerabilità. Includerà funzioni come scan_paths(url_list, config) -> List[ScanResult]. Questo modulo gestirà la creazione delle richieste HTTP (usando requests.Session o un client httpx), l'applicazione degli header, il confronto delle risposte e la raccolta dei risultati. Se si usa il multithreading, questo modulo creerà il ThreadPool e gestirà le attività. Potrebbe definire una piccola data class ScanResult per contenere informazioni su ogni percorso (path, vulnerable: bool, details).
config.py (o settings.py): Contiene il codice per il menu utente e la configurazione. Ad esempio, una funzione che interagisce con l'utente e restituisce un oggetto/dizionario di configurazione con tutte le impostazioni scelte (user_agent, timeout, proxy, flag output_file, ecc.). Se si usano argomenti CLI, questo modulo potrebbe in alternativa analizzare . In sostanza, questa parte isola tutta la gestione dell'input utente e della configurazione.
Ogni modulo sarà progettato per essere modulare e riutilizzabile. Ad esempio, si potrebbe riutilizzare crawler.py per ottenere i link di un sito per altri scopi, o riutilizzare scanner.py per testare questa vulnerabilità su un dato elenco di URL (anche senza crawling).
Gestione delle eccezioni e spegnimento controllato: Implementeremo una gestione robusta delle eccezioni:
Avvolgi le operazioni di rete con try/except (cattura timeout, errori di connessione, ecc.). Se il crawl di una pagina fallisce, registralo e continua con le altre. Se una richiesta di scansione fallisce (ad es., errore proxy), contrassegna quell'endpoint come errore ma continua a scansionare il resto.
Usa blocchi finally o context manager per garantire la pulizia delle risorse. Ad esempio, usa il context async_playwright() o assicurati che browser.close() venga chiamato alla fine del crawling. Allo stesso modo, assicurati che gli handle dei file vengano chiusi dopo la scrittura.
Gestisci KeyboardInterrupt (Ctrl+C): Possiamo intercettare il KeyboardInterrupt nel loop principale e avviare uno spegnimento controllato – ad es., stampare "Stopping, cleaning up…", arrestare i thread (magari usando ThreadPoolExecutor.shutdown(wait=False) per smettere di lanciare nuove attività) e chiudere il browser. Questo previene processi orfani o file bloccati se l'utente interrompe.
Usa il logging per i messaggi di debug (magari tramite la libreria logging di Python). In uno strumento professionale, avresti livelli di logging; ad es., i log di debug potrebbero includere ogni richiesta effettuata, mentre il livello info mostra solo l'avanzamento ad alto livello. L'utente potrebbe impostare un flag verbose per attivarlo. Per impostazione predefinita, potremmo registrare informazioni minime per non sovraccaricare l'output.
Qualità del codice: Aderiremo alle migliori pratiche di codifica:
Segui le linee guida di stile PEP8 per la leggibilità.
Usa nomi di funzioni e variabili significativi.
Aggiungi docstring alle funzioni che ne spieghino scopo e utilizzo.
Usa type hint per le firme delle funzioni (annotazioni di tipo di Python 3) per rendere il codice più facile da capire e per individuare subito i problemi di tipo.
Modularizza le costanti (come l'elenco degli header payload, gli elenchi di estensioni di file statici da ignorare, ecc.) all'inizio o in una configurazione, così da poterle aggiornare facilmente. Ad esempio, HEADER_PAYLOADS = ["middleware:middleware:...","src/middleware:..."] ecc., definite in un unico punto.
Possibilmente includi unit test per alcune funzioni helper (se questo fosse un progetto più grande, anche se per uno strumento a script singolo potrebbe essere tralasciato; ciononostante, progettare pensando alla testabilità è vantaggioso).
Miglioramenti di livello professionale: Per rendere lo script più robusto e pronto per la produzione, possiamo considerare anche:
Supporto all'autenticazione: Consenti all'utente di fornire cookie o credenziali se vuole scansionare una sezione autenticata del sito (anche se la vulnerabilità riguarda il bypass dell'autenticazione, potrebbero esserci scenari in cui è necessario accedere prima per raggiungere determinati link e poi testare il bypass su di essi – anche se il bypass presumibilmente funziona senza autenticazione valida, questo potrebbe aiutare nel crawling di link profondi che non sono pubblici).
File di configurazione: Invece dell'input interattivo (o in aggiunta), consenti di leggere le opzioni da un file di configurazione o da variabili d'ambiente, il che è utile per distribuzioni automatizzate dello scanner.
Formati di output: Fornisci l'output in più formati come JSON o CSV per l'integrazione con altri strumenti. Ad esempio, un flag --json potrebbe esportare i risultati come JSON leggibile da macchina.
Integrazione con framework esistenti: La logica potrebbe essere integrata in un framework di scansione più ampio (ad esempio, trasformandola in un modulo per OWASP ZAP o integrandola con ProjectDiscovery's Nuclei generando un report compatibile). Come minimo, assicurati che l'output dello script identifichi chiaramente la vulnerabilità e gli URL interessati, così da poter essere usato nei report.
Sessioni browser parallele: Se si ha come obiettivo applicazioni molto grandi, considera l'avvio di più contesti browser in parallelo per eseguire il crawling di sezioni diverse contemporaneamente. Playwright può gestire più contesti (ogni contesto è isolato, simile a profili browser separati). Questo potrebbe accelerare notevolmente il crawling, a costo di un maggiore utilizzo delle risorse.
Degradazione controllata: Se Playwright fallisce (ad esempio, l'ambiente manca di un display o di un'installazione corretta), lo script potrebbe ripiegare su un crawl più semplice basato su requests (che potrebbe perdere alcuni link ma è meglio di niente). Questo rende lo strumento più robusto in vari ambienti. Allo stesso modo, se la concorrenza è impostata troppo alta e causa problemi, intercettali e suggerisci all'utente di ridurre il numero di thread.
Seguendo una struttura pulita e queste best practice, lo script sarà più facile da mantenere ed estendere. Ogni componente può essere sviluppato in modo indipendente – ad esempio, migliorando la capacità del crawler di analizzare la navigazione pesante in JavaScript, o aggiornando lo scanner con nuove varianti di header payload se la ricerca futura troverà ulteriori pattern di sfruttamento.
In conclusione, questo design delinea un approccio completo per rilevare CVE-2025-29927 nelle applicazioni web. Sfrutta un browser headless per il crawling profondo, il multi-threading per una scansione efficiente e pratiche di codifica robuste per l'affidabilità. Confrontando le risposte con e senza l'header speciale, è in grado di identificare in modo affidabile gli endpoint vulnerabili in cui il middleware di Next.js viene bypassato. Il risultato è uno strumento di livello professionale che aiuta gli ingegneri della sicurezza e gli sviluppatori a trovare e affrontare rapidamente questa vulnerabilità critica nelle loro applicazioni.
httpx(Opzionale) argparse – per analizzare gli argomenti della riga di comando se vogliamo un'interfaccia CLI invece di un menu interattivo. (modulo integrato)
(Opzionale) rich o colorama – per output console colorati o formattati, per migliorare la leggibilità. (Installazione: pip install rich oppure pip install colorama).
Thread-Safety: Garantiremo una gestione thread-safe dei dati condivisi. L'elenco degli URL da scansionare può essere elaborato con ThreadPoolExecutor.map per semplicità, oppure possiamo usare una coda thread-safe (queue.Queue di Python) e far sì che i thread prelevino da essa fino a svuotarla. L'insieme visited per il crawling viene accesso solo dal crawler (thread singolo, a meno che non facciamo crawling concorrente). I thread dello scanner leggeranno solo dal loro elenco di URL (nessuna modifica delle strutture condivise, a parte eventualmente la registrazione dei risultati, che possiamo proteggere con un lock o raccogliere in una lista thread-safe).
Limitazione della velocità e cortesia: Poiché questo è uno strumento di test di sicurezza, la velocità è una priorità, ma potremmo comunque voler evitare di sovraccaricare il target. All'utente può essere consigliato di impostare un numero ragionevole di thread. Possiamo anche implementare un piccolo ritardo o usare semafori per limitare la concorrenza se necessario. Ad esempio, potremmo non lanciare tutti i thread in una volta se la rete dell'utente o il server potrebbero soffocare. In uno scenario avanzato, un approccio asincrono potrebbe usare un semaforo per consentire, ad esempio, 5 richieste concorrenti alla volta. Questi dettagli possono essere regolati in base ai test sulle prestazioni dello script.
Il payload alternativo per i progetti che utilizzano la directory /src, ad es. "src/middleware:src/middleware:src/middleware:src/middleware:src/middleware"
Opzionalmente, valori a segmento singolo come "middleware" o "src/middleware" per completezza (le versioni precedenti di Next.js potrebbero usare un file _middleware nella directory pages, con un payload leggermente diverso, ma i payload multi-segmento sopra coprono ampiamente i casi noti).
Ognuna di queste richieste verrà effettuata con l'header personalizzato impostato. Ci assicuriamo anche di usare lo stesso metodo (GET) e di includere eventuali header della richiesta di base che potrebbero essere necessari (come cookie o token di autenticazione, se l'utente ne ha forniti per una scansione autenticata, anche se tipicamente scansioniamo come utenti non autenticati).
Se la risposta di base era un errore o reindirizzamento (ad es., 401 Unauthorized, 403 Forbidden, o un redirect al login) e una delle risposte con header iniettato è 200 OK con un corpo significativamente più grande (o comunque indicante che la pagina è stata caricata), questo è un forte indicatore di vulnerabilità. Ad esempio, se /admin normalmente restituisce 403, ma con l'header restituisce 200 e contiene l'HTML della dashboard admin, lo segnaliamo.
In alcuni casi, la differenza potrebbe essere un 302 contro un 200, o un 404 contro un 200. Considereremo un cambio di stato da non-200 a 200 come un probabile segno. Inoltre, se lo stato rimane 200 ma la lunghezza del contenuto cambia drasticamente, ciò potrebbe indicare che l'header ha alterato il comportamento (meno comune per questo particolare bug, ma una possibilità se la pagina normalmente forniva una cosa e con l'header ne forniva un'altra).
Implementeremo controlli come: if base_status_code != 200 and test_status_code == 200: (e magari anche assicurarci che test_body_length > base_body_length o contenga qualche parola chiave autenticata) quindi segnalarlo come vulnerabile. Se la base era un redirect (ad es., 307 verso /login) e il test produce 200, segnaliamo anche quello. In sostanza, "l'accesso era precedentemente negato ma ora è consentito?".
Se lo stato della risposta con l'header è 404 o 500 dove la base era un redirect, potrebbe essere lo scenario di cache poisoning (il bypass del redirect middleware che causa un 404 all'origine). Questo scenario è un po' più difficile da rilevare con una sola richiesta, ma la presenza di un 404 con header quando la base era un redirect potrebbe essere annotata (anche se non è un bypass dell'autenticazione, è comunque un effetto della vulnerabilità). Il nostro focus, tuttavia, è sul rilevamento di un bypass dell'autenticazione (accesso 200 OK).
results.txt se l'utente ha scelto di salvare i risultati. Dovremmo formattare tutto in modo chiaro, ad es.:[*] /admin -> baseline 403, with X-Middleware-Subrequest (payload X) got 200 [VULNERABLE]
Possiamo anche stampare qualcosa come la lunghezza della risposta o un frammento di essa per confermare (magari solo la lunghezza per brevità, ad es., "len: 0 -> 10240 bytes"). Se sono stati provati più payload, potremmo elencare quali hanno avuto successo.
Se il sito non sembra essere affatto un'applicazione Next.js (ad es., non abbiamo trovato alcun /_next/static/ nella homepage, che è un segno rivelatore), potremmo emettere una nota: "Nessun indicatore Next.js trovato, il target potrebbe non usare Next.js – probabilmente non vulnerabile." Ma possiamo comunque procedere in modo generico, poiché il controllo su Next.js è un'ottimizzazione più che una necessità.Questa logica verrà incapsulata in modo pulito. Ad esempio, potremmo avere una funzione scan_endpoint(url, session, header_payloads) che restituisce un oggetto risultato o un dizionario con l'indicazione se è vulnerabile e i dettagli. Incorporeremo controlli robusti per evitare falsi positivi. In particolare, richiedere un cambiamento del codice di stato a 200 (o altre prove evidenti) aiuta a garantire che segnaliamo solo bypass reali. Come indicato nell'analisi di ProjectDiscovery, lo scanner verifica che la risposta abbia stato 200 quando l'header speciale è incluso, per confermare la vulnerabilità.
get_user_config()argparse.ArgumentParserutils.py: Funzioni di utilità, ad es., per stampare banner, formattare le stringhe di output, gestire l'output a colori o helper comuni come is_static_resource(url) (per verificare se un URL punta probabilmente a un file statico). Potrebbe anche includere una funzione per lo spegnimento controllato (da chiamare su SIGINT).
main.py: Lo script entry-point che collega tutto. Dovrà:
config.py).main potrebbe semplicemente trovarsi in fondo a un unico file, ma per pulizia, separarlo è meglio.