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-11349 — Modern Events Calendar Lite <= 7.33.0 — Injeção SQL Não Autenticada | Kitploit
Ferramentas/GitHubGitHub/hann1bl3l3ct3r/cve-2026-11349
Análise de VulnerabilidadesExploraçãoExploração de Aplicações WebSegurança WebTestes de PenetraçãoSegurança de Banco de Dados
GitHubhann1bl3l3ct3r/cve-2026-11349

CVE-2026-11349

Modern Events Calendar Lite <= 7.33.0 — Injeção SQL Não Autenticada

Ver Repositório
112há 3 mesesAinda 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

Modern Events Calendar Lite <= 7.33.0 — Injeção SQL não autenticada via mec_list_load_more (atts[include] / atts[exclude])

Resumo

DetalheValor
PluginModern Events Calendar Lite
Slugmodern-events-calendar-lite
AutorWebnus
Versões afetadas<= 7.33.0 (a versão Lite atual distribuída pelo fornecedor). O bug está presente em toda a faixa pós-w.org; confirmado em laboratório nas versões 6.5.6 e 7.33.0, confirmado estaticamente na 5.21.2. 6.5.6 = último build do wordpress.org (congelado no fechamento de 2022-05-11); 7.33.0 = build atual distribuído a partir de mec.webnus.net
Instalações ativascontagem no wordpress.org ocultada desde o fechamento; historicamente 100,000+. Ainda distribuído/atualizado ativamente pelo fornecedor (Lite via mec.webnus.net; o mesmo código 7.x serve de base para o MEC Pro, vendido ativamente)
CWECWE-89 (Injeção SQL)
VulnerabilidadeInjeção SQL cega não autenticada (baseada em tempo / booleana / baseada em erro)
Privilégio necessárioNenhum (wp_ajax_nopriv_* — pré-autenticação)
Interação do usuárioNenhuma
CVSS v3.17.5 (Alto) — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
StatusVerificado em laboratório de ponta a ponta na 7.33.0 (atual) e 6.5.6 (WordPress 6.6.5, MariaDB 10.x)
CVE / GHSACVE-2026-11349

Descrição

O Modern Events Calendar Lite regista uma família de ações "load more" não autenticadas em admin-ajax.php para seus skins de listagem de eventos (list, grid, masonry, agenda, timeline, tile, custom). Cada handler lê o array atts da requisição, controlado pelo atacante, e o passa por um helper chamado sanitize_deep_array() que — quando chamado com seus argumentos padrão — não realiza nenhuma sanitização — e depois concatena os valores de atts['include'] (e atts['exclude']) crus em um fragmento SQL post_id IN (...) que é executado com $wpdb->get_results() e sem $wpdb->prepare().

Como os pontos de entrada são registrados em wp_ajax_nopriv_*, não é necessária autenticação, conta, nonce ou interação do usuário. Um atacante remoto não autenticado pode injetar SQL arbitrário na cláusula WHERE de um SELECT contra wp_mec_dates e ler qualquer dado no banco de dados do WordPress (hashes de senha de usuários, segredos/chaves de wp_options, dados de outros plugins) por meio de técnicas cegas baseadas em tempo / booleanas / baseadas em erro.


Causa raiz

1. Um "sanitizador" que não sanitiza nada no caminho padrão

app/libraries/main.php:9607:

public function sanitize_deep_array($inputs, $type = 'text', $excludes = array(), $path = '')
{
    if(!is_array($inputs)) return $inputs;

    $sanitized = array();
    foreach($inputs as $key => $val)
    {
        $p = $path.$key.'.';
        if((is_array($excludes) and in_array(trim($p, '. '), $excludes))
            or (is_array($excludes) and !count($excludes)))   // line 9615
        {
            $sanitized[$key] = $val;   // <-- RAW passthrough, no sanitization
            continue;
        }
        // ... (sanitize_text_field / (int) / esc_url / ... only reached when $excludes is non-empty)
    }
    return $sanitized;
}

A guarda (is_array($excludes) and !count($excludes)) faz com que a função seja uma operação nula completa quando $excludes é o array vazio padrão — cada valor é copiado literalmente. A intenção era evidentemente "se houver uma lista de exclusão, pule essas chaves"; a lógica booleana, em vez disso, pula tudo sempre que nenhuma lista de exclusão é fornecida.

2. O chamador não fornece $excludes

app/skins/list.php:499-501 (load_more()):

$this->sf = (isset($_REQUEST['sf']) and is_array($_REQUEST['sf']))
    ? $this->main->sanitize_deep_array($_REQUEST['sf']) : array();
$apply_sf_date = isset($_REQUEST['apply_sf_date']) ? sanitize_text_field($_REQUEST['apply_sf_date']) : 1;
$atts = $this->sf_apply(((isset($_REQUEST['atts']) and is_array($_REQUEST['atts']))
    ? $this->main->sanitize_deep_array($_REQUEST['atts']) : array()), $this->sf, $apply_sf_date);  // line 501

sanitize_deep_array($_REQUEST['atts']) é chamado com um único argumento → $excludes assume o padrão array() → o ramo de operação nula acima → $atts é o $_REQUEST['atts'] cru e não confiável.

3. Concatenação crua na cláusula IN (...)

app/libraries/skins.php:

// line 603 (exclude → NOT IN)
if(isset($this->atts['exclude']) and is_array($this->atts['exclude']) and count($this->atts['exclude']))
    $where_AND .= " AND `post_id` NOT IN (".implode(',', $this->atts['exclude']).")";

// line 606 (include → IN)
if(isset($this->atts['include']) and is_array($this->atts['include']) and count($this->atts['include']))
    $where_AND .= " AND `post_id` IN (".implode(',', $this->atts['include']).")";

Os elementos do array são passados por implode() diretamente para a string SQL, sem cast para inteiro e sem escape. (absint()/(int) em cada elemento teria corrigido isso.)

4. Execução sem prepared statement

app/libraries/db.php:79:

public function select($query, $result = 'loadObjectList')
{
    $query = $this->_prefix($query);          // only swaps `#__` for the table prefix
    $database = $this->get_DBO();
    if($result == 'loadObjectList') return $database->get_results($query, OBJECT_K);  // line 87 — no prepare()
    // ...
}

A string totalmente montada é entregue a $wpdb->get_results() literalmente.

Fluxo de taint (requisição → sink):

$_REQUEST['atts']                                       (attacker-controlled, unauthenticated)
  → app/skins/list.php:501  sanitize_deep_array($atts)  (NO-OP: default empty $excludes)
  → MEC_skin::initialize($atts)                         ($this->atts = raw atts)
  → app/libraries/skins.php:606  "... post_id IN (".implode(',', $this->atts['include']).")"
  → app/libraries/db.php:87  $wpdb->get_results($query) (no prepare)

Alcance

app/skins/list.php:51-52:

$this->factory->action('wp_ajax_mec_list_load_more',        array($this, 'load_more'));
$this->factory->action('wp_ajax_nopriv_mec_list_load_more', array($this, 'load_more'));  // <-- unauthenticated

O registro nopriv torna o endpoint acessível antes da autenticação. O mesmo formato de load_more() e o construtor de consultas compartilhado skins.php estão presentes nos skins irmãos, cada um com sua própria ação wp_ajax_nopriv_*, portanto a mesma injeção é alcançável por qualquer um deles:

Ação AJAX (nopriv)Handler do skin
mec_list_load_moreapp/skins/list.php:497
mec_grid_load_moreapp/skins/grid.php:497
mec_masonry_load_moreapp/skins/masonry.php:229
mec_agenda_load_moreapp/skins/agenda.php:242
mec_timeline_load_moreapp/skins/timeline.php:242
mec_tile_load_moreapp/skins/tile.php:446
mec_custom_load_moreapp/skins/custom.php:233

Nenhum nonce é verificado em load_more(), e a ação não exige que qualquer shortcode do plugin esteja presente em uma página — os handlers AJAX são registrados incondicionalmente no init.


Prova de Conceito (verificada em laboratório, MEC Lite 6.5.6, WordPress 6.6.5, MariaDB 10.x)

Todas as requisições são não autenticadas (sem cookie, sem nonce). O valor injetado é colocado em atts[include][]; o payload fecha os dois parênteses abertos do grupo IN ((...) AND (... IN ( e acrescenta um OR <sleep> de nível superior para que a condição seja avaliada para cada linha varrida e, em seguida, comenta o )) ORDER BY ... final:

TARGET='https://victim.example'          # plain permalinks: use admin-ajax.php directly
Baixar ferramenta