Skip to content
KitploitKITPLOIT
ツールエクスプロイトブログ
Log in
提出
ツールエクスプロイトブログ
提出

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

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

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

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2025-7384 — WordPress Database for Contact Form 7 における重大な未認証の PHP オブジェクトインジェクションのエクスプロイト PoC と根本原因分析。任意のファイル削除による RCE につながります。 | Kitploit
ツール/GitHubGitHub/dungsocool/cve-2025-7384
脆弱性分析エクスプロイトウェブアプリケーション悪用学習と教育ラボと実践
GitHubdungsocool/cve-2025-7384

CVE-2025-7384

WordPress Database for Contact Form 7 における重大な未認証の PHP オブジェクトインジェクションのエクスプロイト PoC と根本原因分析。任意のファイル削除による RCE につながります。

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

人気

すべて見る →

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

すべてのツールを探索

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

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

CVE-2025-7384 — PHPオブジェクトインジェクションによるRCE

プラグイン: Database for Contact Form 7 (contact-form-entries) ≤ 1.4.3
CVSS: 9.8(重大)
CWE: CWE-502 — 信頼できないデータのデシリアライゼーション
認証要件: なし(未認証)
影響: リモートコード実行


目次

  1. 脆弱性の概要
  2. 関連概念
  3. 根本原因分析(ソースコード+デバッグ)
  4. 攻撃チェーン
  5. ステップバイステップの再現(POC)
  6. 影響評価
  7. 修復策

1. 脆弱性の概要

「Database for Contact Form 7」プラグイン(スラッグ: contact-form-entries)バージョン1.4.3以下には、PHPオブジェクトインジェクションの脆弱性が存在します。WordPress管理者が管理パネル内でフォームレコード(エントリ)を閲覧すると、このプラグインは、Contact Form 7を介して未認証ユーザーが送信したデータに対して、インスタンス化を許可するクラスのリストを制御せずに、maybe_unserialize() 関数を直接呼び出します。

攻撃者はログインする必要はありません。通常の問い合わせフォームを送信するだけで、シリアライズされたPHPオブジェクトを任意のフォームフィールドに挿入できます。このデータはデータベースに生のまま保存されます。管理者がそのエントリを開いて閲覧すると、デシリアライゼーション関数が攻撃者の選択したオブジェクトをインスタンス化し、__destruct() や __wakeup() などのマジックメソッドをトリガーして、WordPress環境で利用可能なPOPガジェットに応じて任意の動作を実行します。

重大度レベル: 適切なPOPガジェット(例えば __destruct() メソッドが unlink() を呼び出すクラス)があれば、攻撃者は wp-config.php ファイルを削除し、WordPressを初期インストール画面に戻すことができます → 攻撃者が制御する管理者アカウントで再インストール → ウェブシェルを含むプラグインをインストール → サーバー上で完全なリモートコード実行(RCE)を達成します。

属性値
CVE IDCVE-2025-7384
CVSSスコア9.8(重大)
CWECWE-502 — 信頼できないデータのデシリアライゼーション
影響を受けるプラグインcontact-form-entries (Database for Contact Form 7) ≤ 1.4.3
認証要件なし — CF7フォームを送信する誰でもペイロードを注入可能
トリガー条件管理者が管理パネルで注入されたエントリを閲覧する
最大の影響未認証のリモートコード実行
パッチ適用済みバージョン1.4.4+(unserialize を json_decode または allowed_classes: false に置き換え)

2. 関連概念

PHPのシリアライゼーション/デシリアライゼーション

PHPは serialize() を使用してオブジェクトを構造化されたテキスト文字列に変換し、unserialize() を使用してその文字列からオブジェクトを復元します。unserialize() が信頼できないソース(例: ユーザー入力)からのデータを受け取ると、攻撃者はその時点でPHPメモリにロードされている任意のクラスに属する任意のオブジェクトを構築できます。

PHPマジックメソッド

PHPがオブジェクトのライフサイクル中に自動的に呼び出す特別なメソッドです。この文脈で最も重要なもの:

  • __wakeup() — オブジェクトがアンシリアライズされた直後に呼び出される
  • __destruct() — オブジェクトが破棄される(スコープから外れる、またはリクエストが終了する)ときに呼び出される
  • __toString() — オブジェクトが文字列にキャストされるときに呼び出される

POPチェーン(プロパティ指向プログラミング)

アプリケーション内の既存クラスから複数のマジックメソッドを連鎖させて、危険な一連の動作を構築する手法です。攻撃者は新しいコードを書くわけではなく、既存オブジェクトのプロパティを操作するだけで、マジックメソッドが実行されたときに開発者が意図しないアクションを実行させます。

WordPressにおける maybe_unserialize()

WordPress Coreのラッパー関数です。is_serialized() を呼び出して文字列がシリアライズされたデータかどうかを確認し、真であれば unserialize() を呼び出してオブジェクトを復元します。問題: この関数は、インスタンス化を許可するクラスを制限するための allowed_classes パラメータ(PHP 7.0以降で利用可能)を渡していません。


3. 根本原因分析 — ソースコードからの脆弱性の発見

ステップ1: シンクポイントの発見(シンクハンティング)

まず、プラグインのソースコード全体をgrepしてデシリアライゼーション関数を特定します。これらはPHPで最も危険な関数であり、オブジェクトインジェクションにつながる可能性があります:

grep -rn "unserialize" wp-src/wp-content/plugins/contact-form-entries/

image.png

出力から、maybe_unserialize() の複数の呼び出し箇所が明らかになります。特に includes/data.php の545行目、verify_val() 関数内です:

image 1.png

// data.php lines 538-548
public function verify_val($string){
    if(in_array(substr(ltrim($string),0,1), array('{','['))
       && in_array(substr(rtrim($string),-1), array('}',']'))
    ){
        $val = json_decode($string, 1);
        if(is_array($val)){ $string = $val; }
    } else if(is_serialized($string)){            // line 544
        $string = maybe_unserialize($string);     // ★ line 545 — SINK
    }
    return $string;
}

重要な疑問: $string 変数はどこから来るのか? フィルタリングされずにユーザー入力から来る場合 → これは脆弱性です。

ステップ2: バックワードトレーシング — データはどこから来るのか?

verify_val() がどこで呼び出されているかを探します。同じ data.php ファイル内を逆方向にトレースします:

image 2.png

// data.php lines 520-535
public function get_lead_detail($lead_id){
    global $wpdb;
    $table = $wpdb->prefix . 'vxcf_leads_detail';
    $detail_arr = $wpdb->get_results(
        $wpdb->prepare("SELECT * FROM $table WHERE lead_id=%d", $lead_id),
        ARRAY_A
    );

    foreach($detail_arr as $k => $v){
        if(!empty($v['value'])){
            $detail_arr[$k]['value'] = $this->verify_val($v['value']);  // ← calls verify_val
        }
    }
    return $detail_arr;
}

→ $string はまさに $v['value'] — wp_vxcf_leads_detail データベーステーブルから取得された値です。この関数は、管理者がフォームエントリの詳細を閲覧するときに呼び出されます。

次の疑問: wp_vxcf_leads_detail 内のデータはどこから来るのか? 誰が書き込むのか?

ステップ3: データ書き込みポイント(ソース)の発見

ステップ2から、データがデータベースから取得されることが分かっています。次の疑問: 誰がそこにデータを書き込むのか? data.php 内でINSERTクエリを検索します:

grep -rn "insert" wp-src/wp-content/plugins/contact-form-entries/includes/data.php

image 3.png

詳細は create_lead() 関数のコード(85〜103行目)を参照してください:

image 4.png

98〜99行目で、フォームフィールド(例: your-message)の内容である値 $v が、$wpdb->insert() によってデータベースに直接挿入されます。プラグインはContact Form 7の wpcf7_before_send_mail イベントにフックしているため、ユーザーがフォームを送信するたびに、すべてのフィールドが生のまま保存されます。

追加確認: プラグインは保存前に sanitize_text_field() と sanitize_textarea_field() を使用していますが、これら2つの関数はHTMLタグと特殊HTML文字を除去するだけです。O:21:"VulnerableFileHandler":2:{...} のようなシリアライズされたペイロードにはHTMLタグが含まれていないため、完全にそのまま通過します。

ステップ4: 結論 — 脆弱性の確認

この時点で、完全なフローが確立されました:

Unauthenticated user submits CF7 form (your-message field contains serialized object)
    ↓ sanitize_text_field() — DOES NOT block serialized strings
Saved into wp_vxcf_leads_detail table (raw payload)
    ↓
Admin views entry → get_lead_detail() → verify_val()
    ↓ is_serialized() returns true
maybe_unserialize($string) — line 545 → PHP instantiates arbitrary object
    ↓
Object's __destruct() executes → performs attacker-controlled action

根本原因: data.php:545 の maybe_unserialize() 関数が、未認証ユーザー入力に由来するデータに対して、allowed_classes: false を渡さずに呼び出されています。攻撃者はCF7フォームの your-message フィールドにシリアライズされたPHPオブジェクトを送信するだけで、管理者がエントリを閲覧すると、PHPがそのオブジェクトをインスタンス化して __destruct() マジックメソッドをトリガーします。

ステップ5: デバッガによる検証(Xdebug)

視覚的な証明として、Xdebugを使用して data.php の545行目にブレークポイントを設定します。フォームを介してペイロードを注入し、管理者にエントリを閲覧させた後、デバッガは正確に maybe_unserialize() で一時停止します:

image 5.png

変数パネルには、攻撃者のペイロードを保持する $string が表示されます:

  • $string = "O:21:\"VulnerableFileHandler\":2:{s:9:\"file_path\";s:27:\"/var/www/html/wp-config.php\";s:7:\"cleanup\";b:1;}" → ペイロードはフォーム → データベース → デシリアライゼーション関数へ、ブロックされることなく到達しました

実行行:

  • 545行目: $string=maybe_unserialize($string);

コールスタックは関数呼び出しのシーケンスを示しています:

vxcf_form_data->verify_val        data.php:545
vxcf_form_data->get_entries       data.php:388
vxcf_form::get_entries            contact-form-entries.php:2682
vxcf_form_pages->entries_page     plugin-pages.php:1017
...
WP_Hook->apply_filters            class-wp-hook.php:324
WP_Hook->do_action                class-wp-hook.php:348

→ 分析した正確なフローが確認されます: 管理者がエントリを閲覧 → get_entries() → verify_val() → maybe_unserialize()。


4. 攻撃チェーン

攻撃チェーンは5つのステージで構成されます。攻撃者が実行する必要があるのはステージ1(フォーム送信)だけです。ステージ2〜5は、管理者がエントリを閲覧した後に自動的に発生します。

ステージ1 — ペイロードの注入(未認証)

攻撃者は、メッセージフィールドにシリアライズされたPHPオブジェクトを含むCF7フォームを送信します。

  • エンドポイント: POST /wp-json/contact-form-7/v1/contact-forms/{id}/feedback
  • フィールド your-message に含まれる値: O:21:"VulnerableFileHandler":2:{s:9:"file_path";s:27:"/var/www/html/wp-config.php";s:7:"cleanup";b:1;}
  • プラグインはペイロードを wp_vxcf_leads_detail テーブルに保存 — sanitize_text_field() はシリアライズされた文字列をブロックしない

ステージ2 — デシリアライゼーションのトリガー(管理者待ち)

ツールをダウンロード