2026年5月20日

2026年5月20日

WPScanでWordPressの脆弱性を検査する方法(Docker・APIトークン・定期実行)

WPScan は WordPress 専用の脆弱性スキャナーです。外部からサイトを調べ、WordPress 本体・プラグイン・テーマのバージョン、公開されているユーザー名、設定ファイルのバックアップなどを検出し、API トークンを使うと既知の脆弱性と照らし合わせて表示します。2026年11月時点の最新版は 4.2.0 です。

使う前に確認すること

  • 検査してよいのは、自分が管理する(または許可を得た)サイトだけです。 他人のサイトへのスキャンは、不正アクセスや業務妨害を疑われるおそれがあります。
  • WPScan のライセンスでは、自分のシステムの検査や侵入テストは無料で使えますが、WPScan を組み込んだ有料サービスの提供など商用化にあたる使い方には商用ライセンスが必要です(GitHub の README・LICENSE による)。
  • スキャン中は多数のリクエストを送ります。共用サーバーではサーバー会社の WAF に遮断されたり、アクセス過多として扱われたりすることがあるので、アクセスの少ない時間帯に実行します。

WPScan をインストールする

Docker で実行する(推奨)

Ruby の環境を用意しなくても使えます。

docker pull wpscanteam/wpscan
docker run --rm wpscanteam/wpscan --version

毎回データベース(プラグインやテーマの一覧)を取り直さないように、名前付きボリュームを付けて実行します。

docker run -it --rm -v wpscan-db:/wpscan/.cache/wpscan/db wpscanteam/wpscan --url https://example.com/

gem でインストールする

Ruby 3.3 以上が必要です。

gem install wpscan
wpscan --version

以下では wpscan と書きますが、Docker の場合は docker run -it --rm -v wpscan-db:/wpscan/.cache/wpscan/db wpscanteam/wpscan に読み替えてください。

API トークンを取得する

API トークンが無くてもスキャンはできますが、既知の脆弱性は表示されません。wpscan.com でアカウントを作成すると、プロフィール画面で API トークンを確認できます。

無料枠は 1日 25 リクエスト です(2026年11月時点)。WordPress 本体・プラグイン1つ・テーマ1つごとに1リクエストを使うため、プラグインが 20 個あるサイトでは1回のスキャンでほぼ使い切ります。

トークンはコマンドラインに直接書くより、環境変数で渡すとシェルの履歴に残りません。

read -rs WPSCAN_API_TOKEN && export WPSCAN_API_TOKEN
wpscan --url https://example.com/

Docker の場合は -e WPSCAN_API_TOKEN を付けてコンテナに渡します。

スキャンを実行する

基本のスキャン

wpscan --url https://example.com/

--enumerate を指定しない場合、既定で脆弱なプラグイン・脆弱なテーマ・timthumb・設定ファイルのバックアップ・DB のエクスポート・バックアップフォルダー・ユーザー(ID 1〜10)・メディア(ID 1〜100)を調べます。

--enumerate の選び方

値 調べるもの
vp / ap / p 脆弱なプラグイン / すべてのプラグイン / 人気のプラグイン(どれか1つ)
vt / at / t 脆弱なテーマ / すべてのテーマ / 人気のテーマ(どれか1つ)
cb wp-config.php のバックアップファイル(wp-config.php.bak など)
dbe 公開ディレクトリに置かれた DB のエクスポート
u ユーザー名(u1-20 のように ID の範囲を指定できる)
# 脆弱なプラグイン・テーマ、設定ファイルのバックアップ、ユーザー名を調べる
wpscan --url https://example.com/ --enumerate vp,vt,cb,dbe,u

プラグインの検出は、既定ではページの HTML などから読み取る「passive」です。読み込まれた形跡を残さないプラグインは見落とすことがあるため、より広く調べたい場合は --plugins-detection mixed か aggressive を指定します(リクエスト数が大きく増えます)。

自分のサイトなら --wp-auth で正確に調べる

4.2.0 には --wp-auth オプションがあり、管理者のアプリケーションパスワードを渡すと、REST API からインストール済みのプラグインとテーマの一覧を取得します。外から推測するより正確です(通常のログインパスワードは使えません)。

wpscan --url https://example.com/ --wp-auth 'admin:xxxx xxxx xxxx xxxx xxxx xxxx'

アプリケーションパスワードは「ユーザー」→「プロフィール」で発行でき、使い終わったら同じ画面で取り消せます。詳しくは WordPressのアプリケーションパスワードの使い方 を参照してください。

結果を読む

出力の主な項目と、見るべき点です。

  • WordPress version ... identified:本体のバージョン。括弧内に最新か古いか(Latest や Insecure など)が出ます。
  • [+] プラグイン名:検出したバージョンと最新版。The version is out of date は更新が出ている印です。
  • [!] Title: ...:既知の脆弱性。Fixed in: に修正されたバージョンが出ます。
  • Interesting Finding(s):readme.html の公開、XML-RPC の有効、ディレクトリ一覧の表示など。すべてが危険というわけではなく、参考情報として確認します。
  • User(s) Identified:外部から見えたユーザー名。

見つかった問題を直す

脆弱なプラグイン・テーマ・本体を更新する

# 更新できるものを確認してから更新する
wp plugin list --update=available
wp plugin update contact-form-7
wp theme update --all
wp core update
wp core update-db

まとめて更新する前にバックアップを取り、可能ならテスト環境で動作を確認します。修正版が出ていないプラグインは、無効化して代わりのプラグインを探します。

wp plugin deactivate plugin-slug

設定ファイルのバックアップや DB のエクスポートを消す

cb や dbe で見つかったファイルは、公開ディレクトリから削除します。パスワードが含まれているため、削除後は DB のパスワードの変更も検討してください。

ユーザー名が見えないようにする

WordPress は、投稿のあるユーザーの名前を REST API(/wp-json/wp/v2/users)と投稿者アーカイブ(/?author=1 から /author/ユーザー名/ へのリダイレクト)で公開します。ユーザー名だけでログインされることはありませんが、総当たり攻撃の手がかりを減らせます。

<?php
// wp-content/mu-plugins/hide-users.php

// ログインしていない訪問者には REST API のユーザー一覧・個別取得を出さない
add_filter(
	'rest_endpoints',
	function ( $endpoints ) {
		if ( ! is_user_logged_in() ) {
			unset( $endpoints['/wp/v2/users'], $endpoints['/wp/v2/users/(?P<id>[\d]+)'] );
		}
		return $endpoints;
	}
);

// 投稿者アーカイブをトップページへ転送する(投稿者ページを使っていない場合)
add_action(
	'template_redirect',
	function () {
		if ( is_author() ) {
			wp_safe_redirect( home_url( '/' ), 301 );
			exit;
		}
	}
);

ログイン中のユーザーには一覧を残しているので、ブロックエディターの投稿者の選択は動きます。投稿者ページをサイトで使っている場合は、2つ目の処理は入れないでください。

定期的にスキャンする

WPScan は、脆弱性が1つ以上見つかると終了コード 5 で終わります(0 は脆弱性なし、1〜4 はオプションの誤りや中断・エラー)。これを使うと、結果の JSON を解析しなくても通知の判断ができます。

#!/bin/bash
# /usr/local/bin/wpscan-weekly.sh
set -u

TARGET_URL="https://example.com/"
REPORT_DIR="/var/log/wpscan"
ADMIN_EMAIL="admin@example.com"
REPORT="${REPORT_DIR}/scan-$(date +%Y%m%d).json"

# API トークンは root だけが読めるファイルに置く
WPSCAN_API_TOKEN="$(cat /root/.wpscan-token)"
export WPSCAN_API_TOKEN

mkdir -p "$REPORT_DIR"

docker run --rm -e WPSCAN_API_TOKEN \
  -v wpscan-db:/wpscan/.cache/wpscan/db \
  wpscanteam/wpscan --url "$TARGET_URL" \
  --enumerate vp,vt,cb,dbe \
  --format json --no-banner > "$REPORT"
rc=$?

if [ "$rc" -eq 5 ]; then
  mail -s "[WPScan] 脆弱性を検出: ${TARGET_URL}" "$ADMIN_EMAIL" < "$REPORT"
elif [ "$rc" -ne 0 ]; then
  echo "WPScan の実行に失敗しました(終了コード ${rc})" | mail -s "[WPScan] 実行エラー" "$ADMIN_EMAIL"
fi

# 30 日より古いレポートを削除
find "$REPORT_DIR" -name 'scan-*.json' -mtime +30 -delete
  • mail コマンドは mailutils などのパッケージに含まれます。サーバーからメールを送れる設定(Postfix など)が別に必要です。
  • root の crontab(sudo crontab -e)に、たとえば毎週月曜 3:00 に実行する行を追加します。
0 3 * * 1 /usr/local/bin/wpscan-weekly.sh

無料枠の 25 リクエストに収まるよう、週1回程度に抑え、--enumerate は脆弱なものだけ(vp,vt)にしています。

注意点

  • WPScan が「脆弱性なし」と出しても、安全が保証されるわけではありません。データベースに未登録の脆弱性や、自作のテーマ・プラグインの問題は検出できません。
  • 共用サーバーの WAF やセキュリティプラグインが WPScan の通信を遮断すると、結果に抜けが出ます。遮断された場合は、自分の IP を許可するなど設定を見直します。
  • ログイン試行の制限や二要素認証など、攻撃そのものへの備えは WordPressのブルートフォース攻撃対策 で説明しています。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲