Skip to content
KitploitKITPLOIT
FerramentasExploitsBlog
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-18322 — Análise de causa raiz, verificador de versão passivo e PoC de laboratório para CVE-2026-18322, uma escalada de privilégios não autenticada no plugin WordPress Smart Popup da Supsystic. | Kitploit
Ferramentas/GitHubGitHub/i3it/cve-2026-18322
Escalada de PrivilégiosScanners de VulnerabilidadesAnálise de VulnerabilidadesExploraçãoExploração de Aplicações WebVirtualização para SegurançaSegurança WebTestes de PenetraçãoPapers e PesquisaLabs e Prática
GitHub
2há 26 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
i3it/cve-2026-18322

CVE-2026-18322

Análise de causa raiz, verificador de versão passivo e PoC de laboratório para CVE-2026-18322, uma escalada de privilégios não autenticada no plugin WordPress Smart Popup da Supsystic.

Ver Repositório

CVE-2026-18322 — Smart Popup by Supsystic Privilege Escalation

CVE Severity Affected Fixed in CWE Python Tests License

Pesquisa de segurança sobre CVE-2026-18322, uma vulnerabilidade de escalação de privilégios não autenticada no plugin WordPress Smart Popup by Supsystic (popup-by-supsystic). Este repositório contém uma análise de causa raiz derivada do diff do código-fonte upstream, os patches extraídos, uma ferramenta de detecção (fingerprinter passivo de versão) para identificar instalações afetadas e um laboratório para PoC de exploração.

A vulnerabilidade é pública e corrigida. Este trabalho é publicado para uso defensivo: ajudar operadores a encontrar e remediar hosts afetados.


Versões afetadas

Faixa de versãoStatus
< 1.13.0Vulnerável
>= 1.13.0Corrigida

1.13.0 (lançada em 31.07.2026) é a primeira versão corrigida; ela repara todos os três elos da cadeia descrita abaixo. Veja §1 da análise.


Resumo da vulnerabilidade

Três fraquezas independentes se combinam para criar um administrador não autenticado:

1. Uma colisão de mapa de permissões — havePermissions() combinava dois mapas de permissões com array_merge(). Ambos usam a chave string PPS_USERLEVELS ('userlevels'), e array_merge() sobrescreve chaves string, então a lista curta padrão do controlador base substituiu integralmente a lista do módulo popup — removendo silenciosamente a restrição de administrador de save e de outros nove métodos:

root@kitploit:~
$permissions     = $mod->getController()->getPermissions();      // [... 'save' ...]
$permissionsBase = $mod->getController()->getBasePermissions();  // ['getListForTbl','removeGroup','clear']
$permissions     = array_merge($permissions, $permissionsBase);  // base wins — 'save' is gone

A verificação falha aberta: uma ação ausente do mapa nunca é negada.

2. Um nonce reutilizável enviado por e-mail a estranhos — save ainda exigia um pps_nonce, mas o e-mail de confirmação de assinatura incorporava exatamente essa ação de nonce. Para usuários desconectados, um nonce do WordPress é baseado em uid=0, então o token gerado para um assinante anônimo valida para qualquer atacante anônimo.

3. Nenhuma allowlist de função no lado do servidor — createWpSubscriber() passava a função configurada diretamente para WP_User::set_role(). A lista de funções seguras do plugin (que exclui administrator) era aplicada apenas ao renderizar o dropdown de administração — um controle apenas de UI.

Encadeado: assine para obter um nonce → reutilize-o contra popup::save para definir sub_wp_create_user_role=administrator → dispare o fluxo de assinatura → conta de administrador persistente.

Passo a passo completo com referências de arquivo/linha: docs/ANALYSIS.md.


Detecção — o verificador passivo

poc/cve_2026_18322_check.py determina se um site executa uma versão afetada. Ele nunca tenta exploração: ele emite GETs HTTP simples e lê a versão que a instalação publica sobre si mesma.

Instalação

root@kitploit:~
git clone <this-repo> && cd CVE-2026-18322
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt

requests é recomendado, mas opcional — a ferramenta recorre à biblioteca padrão.

Uso

root@kitploit:~
# Single target
python3 poc/cve_2026_18322_check.py https://example.com

# With supporting evidence
python3 poc/cve_2026_18322_check.py https://example.com -v

# Many targets, concurrently, exporting results
python3 poc/cve_2026_18322_check.py -f targets.txt -t 20 --json results.json
python3 poc/cve_2026_18322_check.py -f targets.txt --csv results.csv --only-vulnerable

# Through a proxy, ignoring TLS errors (lab use)
python3 poc/cve_2026_18322_check.py https://staging.internal -k --proxy http://127.0.0.1:8080

Alvos podem ser fornecidos como argumentos ou via -f (- lê da entrada padrão). Um hostname simples é assumido como https://.

Exemplo

root@kitploit:~
$ python3 poc/cve_2026_18322_check.py https://example.com -v
[VULNERABLE] https://example.com/  (Smart Popup by Supsystic 1.11.2)  < 1.13.0 affected by CVE-2026-18322; upgrade to 1.13.0+
      - asset-version: plugin asset enqueued with ?ver=1.11.2  (https://example.com/)
      - homepage-reference: references /plugins/popup-by-supsystic/  (https://example.com/)
      - readme: plugin readme.txt is publicly readable  (https://example.com/wp-content/plugins/popup-by-supsystic/readme.txt)
      - readme-stable-tag: Stable tag: 1.11.2  (.../readme.txt)

Status

Códigos de saída: 0 = nenhum alvo vulnerável, 1 = pelo menos um vulnerável, 2 = erro de uso.

Como ele detecta

Dois sinais passivos, ambos GETs HTTP simples de recursos públicos:

  1. Cache-busters de assets — o plugin enfileira seu CSS/JS com ?ver=PPS_VERSION (classes/frame.php:410,473), então a homepage frequentemente vaza a versão exata.
  2. readme.txt — Stable tag: é autoritativo e tem precedência sobre um asset em cache potencialmente desatualizado; o changelog serve como fallback.

A varredura da homepage também descobre diretórios wp-content renomeados (por exemplo, /app/ do Bedrock) para que a busca do readme siga o layout real do site.


Segurança

A ferramenta de detecção não tenta exploração. Nenhum exploit armado para este CVE é publicado aqui: o único código que executa a cadeia completa é rigidamente restrito ao laboratório local (veja abaixo).

O verificador passivo realiza apenas fingerprinting de versão. Seu HttpClient expõe nenhum verbo HTTP além de GET — imposto por construção e verificado na suíte de testes, então ele não pode emitir uma requisição que altere estado, mesmo por engano. Ele nunca chama popup::save, envia um parâmetro sub_wp_create_user_role, submete um formulário de assinatura, dispara um e-mail de confirmação, ou cria ou modifica qualquer usuário, popup ou configuração. Ele lê dois recursos públicos — a homepage e readme.txt — e nada mais.

Essa segurança tem um custo, dito claramente: o veredito é tão bom quanto os metadados de versão que o host publica. Tradeoffs e modos de falha: §9.

O exploit do laboratório roda apenas no laboratório

lab/exploit_full_chain.py é a única peça de código aqui que realiza o ataque real, e ele cria um administrador do WordPress. Ele é publicado para que a análise possa ser reproduzida em vez de aceita por confiança — uma afirmação sobre um bug de autorização que não pode ser demonstrada é uma asserção, não um achado. Ele é escrito para a stack descartável em lab/ e para nada mais:

  • Alvos não locais são recusados. O hostname do alvo é resolvido e todo endereço que ele retorna deve ser loopback ou privado RFC1918. Um nome DNS público é rejeitado mesmo se atualmente resolve para um endereço privado — essa é uma forma bem conhecida de apontar uma ferramenta de "laboratório" para produção.
  • --lab-confirm é obrigatório. Ambas as verificações rodam em assert_lab_target() antes da primeira requisição HTTP, então uma invocação rejeitada não toca o alvo de forma alguma.
  • Ele só pode ler a caixa de correio do laboratório. A Fase 1 colhe o pps_nonce reutilizável do e-mail de confirmação de assinatura através da API Mailpit do laboratório (http://localhost:8025/api/v1/…). Não há caminho de código para recuperar esse e-mail de qualquer outro lugar, então a cadeia não tem primeiro passo contra um host fora do laboratório.
  • O laboratório que ele ataca é inacessível de fora da máquina. Todo serviço em lab/docker-compose.yml vincula-se a 127.0.0.1.

Como enviado, ele portanto não pode ser apontado para um site real — ele para em REFUSING TO RUN antes de emitir uma requisição:

root@kitploit:~
$ python3 exploit_full_chain.py https://example.com --lab-confirm
REFUSING TO RUN: example.com resolves to non-local address(es) 104.20.23.154, ...
This script creates a WordPress administrator and is for the local lab only.
To test a real site, use the non-destructive checker in ../poc/.

Essas proteções são estruturais e não decorativas: o script é a cadeia real, e o que o mantém como demonstração é que ele não rodará fora de uma stack local descartável. Por favor, não as remova, e veja SECURITY.md — mudanças que as enfraqueçam, ou um exploit autônomo destinado a rodar fora do laboratório, estão fora do escopo deste repositório. Para descobrir se um site real é afetado, use poc/ — o verificador responde à mesma pergunta sem tocar em nada.

Para uma resposta autoritativa em um host que você controla:

root@kitploit:~
grep -n "array_merge(\$permissions, \$permissionsBase)" \
     wp-content/plugins/popup-by-supsystic/classes/frame.php

Qualquer saída significa que o host é vulnerável — essa linha é precisamente o que a 1.13.0 substituiu.

Use apenas contra sistemas que você possui ou está explicitamente autorizado a testar. Veja SECURITY.md.


Reproduzindo — o laboratório de demonstração

lab/ contém uma stack Docker descartável que executa a vulnerabilidade de ponta a ponta, para que a análise possa ser verificada em vez de aceita por confiança:

root@kitploit:~
cd lab
./setup.sh                                                    # WordPress + plugin 1.12.0
../.venv/bin/python exploit_full_chain.py http://localhost:8080 --lab-confirm
./verify.sh                                                   # confirm from the database
./teardown.sh

Sua saída mais útil é a comparação de versões — requisições idênticas contra três versões:

root@kitploit:~
./setup.sh --plugin-version 1.11.2    # exploit succeeds
./setup.sh --plugin-version 1.12.0    # exploit succeeds
./setup.sh --plugin-version 1.13.0    # exploit fails at phase 2

O laboratório é intencionalmente vulnerável e seu script de exploit cria um administrador do WordPress. Tudo se vincula a 127.0.0.1, e o script não rodará contra nada além de um laboratório local — veja o exploit do laboratório roda apenas no laboratório. Ele não é um scanner; para verificar um site real, use poc/.


Remediação

  1. Atualize para 1.13.0 ou posterior.
  2. Se você não puder atualizar, desative o plugin. Mitigações parciais são fracas — a ação vulnerável é alcançável por qualquer requisição anônima.
  3. Se você executou uma versão afetada com popups de assinatura habilitados, audite para comprometimento: contas de administrador inesperadas, popups com sub_wp_create_user_role definido para uma função privilegiada, e requisições POST para admin-ajax.php carregando pl=pps&mod=popup&action=save.

Consultas e greps de log: §10.


Estrutura do repositório

root@kitploit:~
.
├── README.md
├── SECURITY.md                  Scope, authorized-use policy, disclosure
├── LICENSE                      MIT
├── requirements.txt
├── docs/
│   └── ANALYSIS.md              Full root-cause analysis and fix rationale
├── patches/
│   ├── 01-frame-permission-merge.diff              array_merge() → _mergePermissions()
│   ├── 02-subscribe-role-allowlist-and-nonce.diff  Role allowlist + dedicated nonce
│   └── 03-v1.12.0-confirmation-page-hardening.diff Unrelated hardening added in 1.12.0
├── poc/
│   └── cve_2026_18322_check.py  Passive version fingerprint (GET only)
├── lab/                         Disposable Docker lab — INTENTIONALLY VULNERABLE
│   ├── docker-compose.yml       MariaDB + WordPress 1.12.0 + Mailpit (loopback only)
│   ├── setup.sh / teardown.sh   Bring the lab up / destroy it
│   ├── exploit_full_chain.py    Full attack chain — CREATES AN ADMIN; lab-gated
│   └── verify.sh                Independent confirmation from the database
├── scripts/
│   └── fetch_versions.sh        Export plugin versions from SVN and regenerate diffs
└── tests/
    └── test_check.py            Offline unit tests for the passive checker

Desenvolvimento

root@kitploit:~
pip install -r requirements.txt pytest
python3 -m pytest tests/ -v

A suíte é totalmente offline — usa fixtures gravadas, nunca alvos ao vivo. Ela cobre triagem de versão através da fronteira 1.13.0, normalização de alvos, e as regras de evidência que decidem cada status.

Propriedades de segurança são verificadas, não apenas documentadas: que uma varredura completa não emite requisições que alteram estado, e que HttpClient não expõe nenhum verbo HTTP além de GET.

Duas regressões encontradas durante o desenvolvimento estão travadas: um readme.txt com CRLF derrotando o parsing ancorado em linha, e uma página de erro HTTP sendo contada erroneamente como evidência do plugin.

Para reproduzir a análise a partir das fontes upstream:

root@kitploit:~
./scripts/fetch_versions.sh          # exports 1.11.2 / 1.12.0 / 1.13.0 and regenerates patches/

Licença

MIT — veja LICENSE. O plugin analisado é GPLv2-ou-posterior e não é redistribuído aqui; scripts/fetch_versions.sh o busca do repositório SVN oficial do WordPress.

Baixar ferramenta
StatusSignificado
VULNERABLEPlugin detectado em < 1.13.0
NOT_VULNERABLEPlugin detectado em >= 1.13.0
PLUGIN_DETECTED_VERSION_UNKNOWNPlugin presente, versão não determinável — verifique manualmente
PLUGIN_NOT_DETECTEDNenhuma evidência do plugin (não é prova de ausência)
ERRORAlvo inacessível ou malformado