
🔥 XSS2Shell — Scanner CVE-2026-64638 e Kit de Ferramentas PoC
Scanner em massa orientado a comportamento e gerador de PoC de nível evidencial
para a cadeia XSS-para-RCE de pré-autenticação do WordPress que afeta mais de 500 milhões de sites.
Apenas detecção. Sem weaponização. Construído para programas de bug bounty e blue teams.
O que é isso? • Início Rápido • Dorks do Shodan • Uso • Matriz de Decisão • Detecção • Perguntas Frequentes
Caçe instâncias WordPress potencialmente vulneráveis pela internet antes de escanear:
http.component:"wordpress" -http.title:"Just a moment"
Encontra sites WordPress excluindo as páginas do modo "I'm Under Attack" do Cloudflare / proteção contra bots, que bloqueiam ou desafiam requisições automatizadas.
http.component:"wordpress" http.title:"Log In"
Retorna apenas páginas de login do WordPress — a superfície de ataque exata do CVE-2026-64638.
http.component:"wordpress" "wp-content" "?ver=7.0" -"?ver=7.0.3"
Sinaliza instâncias WordPress 7.0.x sem o patch 7.0.3 por fingerprinting de versão de assets.
http.component:"wordpress" http.html:"wp-login.php"
Captura sites onde o wp-login.php está acessível, mas pode não ser a página atual — cobertura mais ampla.
http.component:"wordpress" -http.title:"Just a moment" -http.title:"Attention Required" -org:"Cloudflare"
Filtro agressivo que elimina a maioria dos alvos atrás do Cloudflare. Use ao escanear em escala com --active — o Cloudflare fará rate-limit ou bloqueará a requisição de sondagem.
Dica: Exporte os resultados do Shodan com
shodan downloade canalize os hostnames diretamente paraxss2shell_mass.py -i.
Em 7 de agosto de 2026, a pwn.ai divulgou o CVE-2026-64638 (XSS2Shell) — uma vulnerabilidade crítica de cross-site scripting de pré-autenticação no WordPress Core que encadeia até a execução remota de código no servidor. [citation:pwn.ai blog]
A falha explora uma divergência de parsing entre a função strip_tags() do PHP e a wp_kses_post() do WordPress:
strip_tags() usa < imediatamente seguido por uma letra para identificar tags HTML. < area id=...> (com um espaço) é tratado como texto — ele sobrevive.wp_kses_post() (KSES) reconhece < area como um elemento <area> válido — e <area> está na allowlist do KSES. [citation:pwn.ai blog]Um único login falho com um nome de usuário especialmente criado < area id=ajaxurl href=/?rest_route=/&_method=GET&_jsonp=alert>... burla ambos os sanitizadores, é renderizado como DOM ativo na página de login, sequestra o script user-profile.js do próprio WordPress via DOM clobbering e dispara alert() na origem do WordPress — zero cliques, zero autenticação, zero cookies necessários. [citation:pwn.ai blog]
Escalado para um administrador logado? A mesma primitiva rouba Application Passwords via Same Origin Method Execution (SOME), faz upload de um plugin malicioso e executa PHP como www-data. [citation:pwn.ai blog] [citation:hadrian.io blog]
Afetado: WordPress 6.4 até 7.0.2 — corrigido no 7.0.3 com backports para 4.7+.
Impacto: ~500 milhões de sites na época da divulgação. [citation:pwn.ai blog]
| Recurso | Link |
|---|---|
| Divulgação Original (pwn.ai) | pwn.ai/blog/xss2shell |
| Análise Técnica da Hadrian | hadrian.io/blog/wordpress-xss2shell |
| Advisory do WordPress (GHSA) | GHSA-52p2-r8wf-jcrf |
| Pesquisa sobre Ataques SOME (2022) | pwn.ai/blog/bypass-csp-using-wordpress |
| Lançamento do WordPress 7.0.3 | wordpress.org/news/2026/08/wordpress-7-0-3-release |
Este é um kit apenas de detecção. Ele não weaponiza a vulnerabilidade — fornece a pesquisadores de segurança, caçadores de bug bounty e blue teams tudo o que é necessário para:
"Uma string de versão diz qual nível de patch o código deveria ter.
Somente o comportamento do sanitizador da página de login diz se a falha dispara."
Hosts gerenciados aplicam backports de patches de segurança silenciosamente, sem alterar as strings de versão. Plugins de hardening de login substituem a mensagem de erro por completo, eliminando o canal de reflexão mesmo em versões inseguras. Scanners baseados apenas em versão produzem falsos positivos e falsos negativos. Este scanner envia uma única sondagem benigna e classifica o comportamento real do sanitizador.
git clone https://github.com/jakestone/xss2shell.git
cd xss2shell
pip install -r requirements.txt
# Passive — no probes sent to target, version + endpoint fingerprinting only
python3 xss2shell_mass.py -i domains.txt -o results
# Active — sends ONE benign failed-login per host (authorized assets only!)
python3 xss2shell_mass.py -i domains.txt -o results --active --workers 80
# Single target
python3 make_poc.py --target https://blog.example.com
# Batch from scanner output
python3 make_poc.py --from-results results.csv -o pocs/
Abra o .poc.html gerado no seu navegador enquanto grava vídeo → se alert() disparar, você capturou evidência de XSS pré-autenticação.
xss2shell_mass.py)usage: xss2shell_mass.py [-h] -i INPUT [-o OUTPUT]
[--active] [--workers WORKERS]
[--timeout TIMEOUT] [--quiet]
| Flag | Descrição |
|---|---|
-i, --input | Arquivo com um host por linha (domínio simples ou URL completa) |
-o, --output | Caminho base para os arquivos de saída (gera .csv + .json) |
--active | Ativa a sondagem comportamental — um login falho por host |
--workers | Tamanho do pool de threads (padrão: 50, máx. ~200 para boas conexões) |
--timeout | Timeout HTTP em segundos (padrão: 10) |
--quiet | Imprime apenas confirmed_vulnerable, vulnerable e likely_vulnerable |
?ver= de assets, referências a wp-content)user-profile.js enfileirado, versões de assets do core/?rest_route=/&_method=GET&_jsonp=<random> — o caminho JSONP está aberto?--active)Envia um único login falho com o nome de usuário < area id=<RANDOM> href=/x2s> e classifica a resposta HTML:
bypass — elemento <area> real com nosso marcador sobreviveu → divergência strip_tags/KSES CONFIRMADAescaped — marcador presente, mas codificado como entidade → patch ou hardening presentestripped — erro padrão do WP exibido, tags removidas → acevomod ou corrigidoclosed — nenhuma reflexão do nome de usuário → plugin de hardening de login instaladomake_poc.py)usage: make_poc.py [-h] [--target TARGET] [--from-results FROM_RESULTS]
[-o OUTDIR]
Gera a página de PoC publicada pela pwn.ai para cada alvo — o formulário HTML exato que dispara alert() em um WordPress sem patch. Três variantes de payload estão incluídas nos comentários:
| Variante | Valor de href | Quando usar |
|---|---|---|
| Padrão | /?rest_route=/&_method=GET&_jsonp=alert | WordPress padrão |
| Envelope | /?rest_route=/&_method=GET&_envelope=1&_jsonp=alert | REST retorna 401 (envolve em 200) |
| Pivô de WAF | /wp-json/wp/v2/statuses/publish?_jsonp=alert&_method=GET | ?rest_route= bloqueado pelo WAF |
O mecanismo de decisão do scanner combina a classificação de versão (da API stable-check do WordPress.org) com evidências comportamentais para produzir 10 vereditos distintos:
| Veredito | Condições |
|---|---|
confirmed_vulnerable 🔴 | Versão é insegura E o marcador da sondagem sobreviveu como elemento <area> E o gadget user-profile.js está presente |
vulnerable 🔴 | Versão é insegura segundo o wordpress.org; sondagem comportamental NÃO executada (re-executar com --active) |
likely_vulnerable 🟠 | Marcador da sondagem sobreviveu, MAS user-profile.js não enfileirado (gadget de disparo automático publicado ausente) |
mitigated 🟣 | Versão é insegura, MAS o marcador da sondagem foi escapado/removido/fechado (backport silencioso ou hardening) |
likely_patched 🟢 | Versão oculta/desconhecida, MAS o marcador da sondagem foi escapado/removido |
patched 🟢 | Versão é latest ou outdated (tem backports de segurança) |
not_wordpress ⚫ | Nenhum fingerprint do WordPress detectado |
unreachable ⚫ | Falha de conexão (timeout, SSL, DNS) |
inconclusive 🟡 | Bloqueio de WAF, desafio do Cloudflare, versão oculta sem sondagem ou página de login ausente |
error 🟡 | Falha inesperada durante o scan |
Colunas do CSV: host, url, status, checker_status, wp_version, branch_status, evidence, http, ms, error
A coluna checker_status mapeia para o vocabulário do verificador público da pwn.ai (vulnerable / patched / not_wordpress / unreachable / inconclusive / error) para correlação direta.
Se você está no lado da defesa, estes são os sinais forenses que esta vulnerabilidade deixa:
# Primary signal: encoded '<' in the log parameter
POST /wp-login.php → log=%3C... (URL-encoded < in username field)
# Higher confidence: paired with REST pivoting
GET /?rest_route=/&_method=GET&_jsonp=... # JSONP callback
GET /wp-json/wp/v2/statuses/publish?_jsonp=... # WAF-bypass variant
# Escalation stage indicators
GET /wp-admin/authorize-application.php?success_url=<off-origin>
POST /wp-admin/update.php?action=upload-plugin
GET /wp-content/plugins/<random>/shell.php
Bloqueie POST /wp-login.php quando o parâmetro log contiver %3C (< codificado em URL). Nomes de usuário válidos do WordPress nunca contêm colchetes angulares. Não restrinja a tags específicas — o KSES permite tab, nova linha e carriage return após < e qualquer tag da allowlist, portanto uma regra específica de tag é trivialmente contornada. [citation:hadrian.io blog]
O callback _jsonp= no estágio de escalada usa pontos para percorrer propriedades (ex.: window.opener.approve.click). Sinalize requisições REST com callbacks JSONP pontuados como fortes indicadores de exploração. [citation:hadrian.io blog]
THIS TOOL IS DETECTION-ONLY. IT DOES NOT:
✗ Weaponize the JSONP callback beyond the public alert()
✗ Include admin-lure pages or Application Password capture
✗ Include REST abuse, plugin upload, or PHP shell code
✗ Execute more than one failed login per target per scan
YOU MUST:
✓ Only scan assets you own or have written authorization to test
✓ Only generate PoCs for your own browser on your own server
✓ Never send PoC links to site admins/users
✓ Never escalate past alert() without program written approval
✓ Follow the bug bounty program scope and rules
This toolkit exists for authorized security research, bug bounty
programs, and defensive detection engineering. Misuse is your
responsibility.
xss2shell/
├── README.md ← You are here
├── xss2shell_mass.py ← Behavior-first mass scanner (v1.1.0)
├── make_poc.py ← Evidence-grade PoC page generator
├── requirements.txt ← Python dependencies (just `requests`)
├── .gitignore ← Ignores scan outputs and cache
└── example/
├── domains.txt ← Example input file
└── example_output.csv ← Example scan output
P: Por que não verificar apenas a string de versão do WordPress?
R: Hosts gerenciados (WP Engine, Kinsta, Pantheon, etc.) frequentemente aplicam backports de patches de segurança sem alterar a versão. Plugins de hardening de login substituem a mensagem de erro por completo. Ambos os casos produzem falsos positivos em scanners baseados apenas em versão e falsos negativos para versões ocultas. Este scanner testa o comportamento real do sanitizador.
P: A sondagem --active é perigosa?
R: Não. Ela envia exatamente um login falho com um nome de usuário marcador benigno. Não tenta executar JavaScript, não enumera nomes de usuário válidos e não dispara nenhum exploit real. É menos intrusiva do que uma tentativa de login padrão.
P: Esta ferramenta pode ser usada para scans não autorizados?
R: Não. A sondagem ativa envia um POST HTTP para /wp-login.php, que é uma requisição ao servidor alvo. Use apenas em ativos que você possui ou tem autorização escrita explícita para testar.
P: Qual é a diferença entre vulnerable e confirmed_vulnerable?
R: vulnerable significa que a API do WordPress.org diz que a versão é insegura, mas ainda não confirmamos a divergência strip_tags/KSES comportamentalmente. confirmed_vulnerable significa que enviamos uma sondagem e o elemento <area> sobreviveu a ambos os sanitizadores — a cadeia publicada pode disparar.
P: Posso usar isto em relatórios do meu programa de bug bounty?
R: Sim! A coluna checker_status mapeia diretamente para o vocabulário do verificador público da pwn.ai para fácil correlação. Combine os resultados do scan com evidências em vídeo de PoC geradas pelo make_poc.py para relatórios completos.
P: Isto detecta a cadeia de RCE?
R: Não. Este kit detecta o ponto de entrada de XSS pré-autenticação. A cadeia completa de RCE exige um administrador logado, Application Passwords habilitadas e permissões de upload de plugin — condições que este scanner não avalia. O scanner foca no que é observável externamente: o bypass do sanitizador.
Construído por 0xlipon • Apenas detecção • Somente para uso autorizado