CVE-2025-11833: Post SMTPのメールログ漏洩による未認証アカウント乗っ取り
概要
- CVE: CVE-2025-11833
- プラグイン: Post SMTP – WordPress SMTP Plugin
- 影響バージョン: 全バージョン <= 3.6.0
- 修正バージョン: 3.6.1(2025年10月29日リリース。攻撃は2025年11月1日から確認)
- CVSS: 9.8 (Critical)
- 認証: 不要(未認証)
- 種別: 認可チェック欠落 / メールログ経由の未認証アカウント乗っ取り
2025年10月に修正が提供されたにもかかわらず、11月1日以降に実際の攻撃が急増したこの脆弱性は、約40万件のWordPressサイトで利用されているSMTPプラグイン「Post SMTP」に存在します。Wordfenceは最初の数日間で4,500件を超える悪用試行をブロックしました。
攻撃の本質はシンプルかつ致命的です。プラグインが送受信したメールをログとして保存する機能において、そのログへのアクセス制御が欠落していました。攻撃者は管理者アカウントのパスワードリセットメールをログから読み取り、リセットリンクをクリックして完全な管理者権限を取得できます。パスワードも既存のセッションも必要ありません。
何が起きたか
Post SMTPは、WordPressのデフォルトメール機能(wp_mail())をSMTP経由に切り替えるプラグインです。メール送信の失敗を診断するために、送信したすべてのメールの内容・宛先・送信日時をデータベースに記録する「メールログ」機能を持っています。
脆弱性の根本原因は、このメールログへのアクセスを制御するREST APIエンドポイントの実装にあります。プラグインの __construct 関数内でREST APIルートを登録していますが、そのルートに対するパーミッションコールバック(permission_callback)が適切に設定されていませんでした。
問題のあったコードは概念的に以下のようなものです:
// 脆弱なコード(概念的な例)
add_action( 'rest_api_init', function () {
register_rest_route( 'post-smtp/v1', '/logs', [
'methods' => 'GET',
'callback' => [ $this, 'get_email_logs' ],
// permission_callback が欠落、または常に true を返す実装になっていた
'permission_callback' => '__return_true',
] );
} );
permission_callback に __return_true が指定されているか、チェックが完全に欠落している場合、WordPressはそのエンドポイントを認証なしで誰でも呼び出せる状態にします。結果として、ログインしていない外部の攻撃者が REST API 経由でメールログ全件を取得できました。
メールログには、WordPressが生成したすべてのシステムメールが含まれます。新規ユーザー登録の通知、お問い合わせフォームの内容、そして—最も重要なことに—パスワードリセットリンクも平文で記録されています。
攻撃の仕組み
攻撃フローは完全に自動化可能であり、技術的な知識がほとんど不要なほどシンプルです。
-
ターゲットの特定: Post SMTPが3.6.0以下であるWordPressサイトを特定する。WPScanや類似のツール、あるいはNyambushのようなスキャナーでバージョン情報を取得できる。
-
管理者メールアドレスの取得: WordPressはデフォルトで
wp-json/wp/v2/usersREST APIから著者情報を公開している。または/?author=1のURLでユーザー名が確認できる場合がある。管理者のメールアドレスは管理者権限なしに直接取得できないが、次のステップでは不要。 -
パスワードリセットのトリガー: WordPressの標準的なパスワードリセットページからリセットリクエストを送信する。
POST /wp-login.php?action=lostpassword
user_login=admin
このリクエストにより、WordPressは管理者のメールアドレス宛にパスワードリセットリンクを含むメールを送信する。そのメールはPost SMTPによってデータベースに記録される。
- メールログへの未認証アクセス: 認証なしでPost SMTPのREST APIエンドポイントを呼び出し、送信済みメールの一覧を取得する。
GET /wp-json/post-smtp/v1/logs
レスポンスには以下のような形式でログが返される:
[
{
"id": 42,
"subject": "【サイト名】パスワードのリセット",
"to": "[email protected]",
"body": "...パスワードをリセットするには以下のリンクをクリックしてください:\nhttps://example.com/wp-login.php?action=rp&key=AbCdEfGhIjKlMnOpQrSt&login=admin...",
"created_at": "2025-11-02 03:14:15"
}
]
- リセットリンクを使ってパスワードを変更: ログから抽出したリセットリンクにアクセスし、新しいパスワードを設定する。このリンクはWordPress標準の手順で発行されたものであるため、WordPressはこれを正当なリセット操作として処理する。
GET /wp-login.php?action=rp&key=AbCdEfGhIjKlMnOpQrSt&login=admin
- 管理者としてログイン: 設定した新しいパスワードで管理者アカウントにログインし、サイトの完全な制御を取得する。
攻撃全体で必要な認証情報はゼロです。WordPressの正規機能(パスワードリセット)とPost SMTPの欠陥(ログへの無制限アクセス)を組み合わせた、エレガントでありながら破壊的な攻撃です。
実際の被害
- 約40万サイトに影響する可能性がある
- Wordfenceは脆弱性公開後の最初の数日間だけで4,500件超の攻撃試行をブロックした
- 認証が不要なため、攻撃の自動化・大規模スキャンが容易に実現できる
- 管理者アカウントの完全な乗っ取りが可能であり、サイトコンテンツの改ざん・マルウェア設置・バックドア埋め込みが行われた報告がある
- メールログには過去に送信されたすべてのシステムメールが含まれるため、パスワードリセット以外の機密情報(お問い合わせ内容、ユーザー登録情報など)も同時に流出する
- 修正版(3.6.1)のリリースから攻撃開始まで約3日しかなかった。パッチ適用が遅れたサイトは短期間で無防備な状態にあった
修正と教訓
修正: バージョン3.6.1(2025年10月29日リリース)で修正済み。REST APIエンドポイントの permission_callback に適切なCapabilityチェック(manage_options または同等の管理者権限)が追加され、認証済みの管理者ユーザーのみがメールログにアクセスできるようになりました。
教訓:
- REST APIエンドポイントには必ず
permission_callbackを実装する: WordPressのREST API登録でpermission_callbackを省略するか__return_trueを指定することは、そのエンドポイントを完全に公開することを意味する。状態を読み取るだけのエンドポイントであっても、機密情報を含む場合は適切な認可チェックが必須 - ログデータを機密情報として扱う: デバッグ・診断用のログには、メール本文・リセットリンク・APIトークンなど、本番環境では決して外部に漏れてはならない情報が含まれる可能性がある。ログへのアクセスは本番環境では管理者のみに制限すること
- 修正のリリースからパッチ適用までの速度: この事例では修正版リリースからわずか3日で攻撃が始まった。月次や週次の更新サイクルでは間に合わない。脆弱性の重大度に応じて即時適用の判断基準を設けること
- パスワードリセット機能はセキュリティの要所: パスワードリセットのフローに関わる実装はすべて高い注意が必要。メール配信、ログ保存、トークン管理のいずれかに欠陥があると、認証機構全体が無効化される
- プラグインのアクティブ監視: 40万インストールのプラグインに重大な脆弱性が存在した期間中、多数のサイトが無防備だった。インストール済みプラグインとそのバージョンを継続的に監視し、CVE公開時に即座にアラートを受け取る仕組みが必要
Nyambushでの検出
NyambushはWordPressプラグインのバージョン情報を自動的に検出し、既知の脆弱性データベースと照合します。Post SMTP 3.6.0以下が動作しているサイトを検出した場合、CVSSスコア9.8の「Critical」警告とともに即座に通知します。
さらに、Post SMTPのメールログREST APIエンドポイント(/wp-json/post-smtp/v1/logs)への外部からのアクセス可否を実際に検査し、認証なしでログが取得できる状態であれば脆弱性が活性化していることを確認したうえで警告を発します。継続監視モードでは、プラグインが修正バージョンに更新されるまでアラートを維持し、3.6.1以上への更新を確認した時点で自動的に解除します。