2026年7月11日

2026年7月11日

WordPressのバックドアを見つけて除去する手順|WP-CLIのチェックサム検証と再侵入対策

バックドアは、攻撃者が一度侵入したあとに「いつでも戻ってこられる入口」として仕込むファイルやコードです。表に見えるスパムページやリダイレクトだけを消しても、バックドアが残っていれば数日で同じ改ざんが繰り返されます。この記事では、WP-CLIを使える環境(SSHで入れるVPSやレンタルサーバー)を前提に、バックドアを探す場所と、除去したあとに入口と認証情報を塞ぐ手順を説明します。

バックドアが疑われる状況

次のような兆候があれば、表面の症状だけでなくバックドアの有無まで調べます。

  • 削除したはずのスパムページや不審なリダイレクトが、しばらくすると復活する
  • 作った覚えのない管理者ユーザーがいる
  • wp-content/uploads の中にPHPファイルがある
  • 検索エンジン経由の訪問者だけが別サイトへ転送される
  • 知らないプラグインやテーマ、wp-content/mu-plugins 内のファイルが増えている
  • ホスティング会社から、不正なファイルや大量メール送信の通知が届いた

作業の前に現状を保存する

調査の前に、ファイルとデータベースを丸ごとコピーしておきます。このコピーは感染した状態のままなので、復元用ではなく「何が起きたかを後で調べるための資料」として扱い、公開ディレクトリの外に置きます。

cd /var/www/html

# 訪問者にメンテナンス画面を表示する(作業中の被害拡大を防ぐ)
wp maintenance-mode activate

# データベースとファイルを保存(保存先は公開ディレクトリの外)
mkdir -p ~/incident
wp db export ~/incident/db-$(date +%Y%m%d).sql
tar czf ~/incident/files-$(date +%Y%m%d).tar.gz -C /var/www html

Webサーバーのアクセスログも、ローテーションで消える前にコピーしておきます。ログの場所はサーバーによって異なり、Debian/Ubuntu の Apache なら /var/log/apache2/、Nginx なら /var/log/nginx/ が一般的です。レンタルサーバーでは管理画面からダウンロードする形式が多いので、各社のマニュアルで確認してください。

コアファイルを公式のチェックサムと照合する

WordPress本体のファイルは、WordPress.org が公開しているチェックサムと照合できます。

wp core verify-checksums --include-root

改ざんされたファイルは File doesn't verify against checksum、本来存在しないファイルは File should not exist という警告で表示されます。--include-root を付けると、WordPressのルートディレクトリにある、WordPress本体以外のファイルやフォルダーについても警告が出ます。wp-admin や wp-includes の中に紛れ込んだ見慣れないPHPファイルは、バックドアの典型的な置き場所です。

日本語版のWordPressを使っている場合、言語の違いで警告が出るときは --locale=ja を付けて照合します。

プラグインとテーマを照合する

WordPress.org で配布されているプラグインは、同じようにチェックサムで照合できます。

wp plugin verify-checksums --all

この方法で検証できるのは、WordPress.org がチェックサムを公開しているプラグインだけです。有料プラグインや自作プラグインは照合できないので、配布元から入手し直して入れ替えます。テーマにはチェックサムを照合するコマンドがありません。テーマも配布元のファイルで入れ替えるか、手元の正しいコピーと比較します。

使っていないプラグインとテーマは、調査の対象を減らすためにも削除しておきます。

wp plugin list --fields=name,status,version
wp theme list --fields=name,status,version

バックドアが置かれやすい場所を点検する

チェックサムで照合できない場所は、目で確認します。

uploads ディレクトリのPHPファイル

wp-content/uploads は画像などのメディアを置く場所で、通常はPHPファイルが入りません。見つかったものは中身を確認します。

find wp-content/uploads -type f \( -name '*.php' -o -name '*.phtml' -o -name '*.phar' \)

mu-plugins とドロップイン

wp-content/mu-plugins に置いたPHPは、管理画面のプラグイン一覧で無効化できないまま自動で読み込まれます。wp-content 直下の advanced-cache.php や object-cache.php などのドロップインも同様です。

wp plugin list --status=must-use
wp plugin list --status=dropin
ls -la wp-content/mu-plugins/

キャッシュ系プラグインやホスティング会社が設置したものもあるので、どれが正規のものか一つずつ確かめます。

wp-config.php、.htaccess、.user.ini

wp-config.php の末尾や先頭に、見覚えのない include や長い文字列が足されていないか確認します。.htaccess と .user.ini では、auto_prepend_file(すべてのPHPの前に指定ファイルを読み込ませる設定)や、外部サイトへの書き換えルールがないかを見ます。

find . -name '.htaccess' -o -name '.user.ini' | xargs grep -n -i -E 'auto_prepend_file|auto_append_file|RewriteRule'

不審なコードを検索する

難読化されたバックドアには、eval や base64_decode などの関数と、非常に長い1行の文字列がよく使われます。

# 難読化によく使われる関数を含むPHPファイル
grep -rlE --include='*.php' '(eval|assert|base64_decode|gzinflate|str_rot13)[[:space:]]*\(' wp-content

# 3000文字を超える行を含むPHPファイル
grep -rlE --include='*.php' '^.{3000,}' wp-content

# 最近14日以内に変更されたPHPファイル
find . -type f -name '*.php' -mtime -14 -printf '%TY-%Tm-%Td %TH:%TM %p\n' | sort

正規のプラグインも base64_decode などを使うため、ヒットしたファイルがすべて不正とは限りません。逆に、攻撃者はファイルの更新日時を書き換えることがあるので、更新日時だけで安全と判断しないでください。中身を開いて、ほかのファイルと書き方が明らかに違うもの、意味のない変数名と長い文字列ばかりのものを優先して確認します。

データベースと予約処理を確認する

ファイルを消しても、データベースに残った管理者アカウントや予約処理から再び侵入されることがあります。

# 管理者ユーザーの一覧(登録日時も見る)
wp user list --role=administrator --fields=ID,user_login,user_email,user_registered

# 予約されている処理(見覚えのないフック名がないか)
wp cron event list --fields=hook,next_run_relative,recurrence

# 投稿やオプションに埋め込まれたスクリプト
wp db search '<script' --all-tables-with-prefix

wp db search の結果には、埋め込みコードなど正規のものも含まれます。外部ドメインのスクリプトを読み込んでいる箇所や、オプションに入っている長いコードを重点的に確認します。

アクセスログから侵入口を探す

バックドアは外部からPOSTリクエストで呼び出されることが多いため、WordPressが通常受け付けないファイルへのPOSTを探します。次の例は、Apache や Nginx の標準的なログ形式(7列目がリクエストのパス)を前提にしています。

grep '"POST ' /var/log/nginx/access.log \
  | grep -v -E 'wp-login\.php|admin-ajax\.php|wp-cron\.php|xmlrpc\.php|/wp-json/' \
  | awk '{print $7}' | sort | uniq -c | sort -rn | head -30

ここで見つかったファイル名は、先の調査結果と突き合わせます。最初にそのファイルが呼ばれた日時から、どのプラグインの脆弱性やどのアカウントが入口になったかを推定できる場合があります。

バックドアを除去する

調査で見つけたものを取り除き、公式の配布物で上書きします。

# WordPress本体を、現在と同じバージョンの公式ファイルで上書き(wp-content は対象外)
wp core download --skip-content --force --version=$(wp core version)

# WordPress.org のプラグインを入れ直す(例: contact-form-7)
wp plugin install contact-form-7 --force

# 見覚えのない管理者を削除し、投稿は別のユーザーに引き継ぐ(IDは調査結果に合わせる)
wp user delete 15 --reassign=1

日本語版のWordPressを使っている場合は --locale=ja を付けます。wp core download --force はファイルを上書きしますが、余分なファイルは削除しません。verify-checksums で File should not exist と出たファイルや、uploads内のPHPファイルは手作業で削除します。プラグインを入れ直すときは、脆弱性が修正された最新版にします。

除去したら、もう一度確認します。

wp core verify-checksums --include-root
wp plugin verify-checksums --all

侵入より前の日付で、改ざんされていないことがわかっているバックアップがあれば、それを戻すほうが早い場合もあります。ただし、その場合も侵入口になった脆弱性は残っているので、次の節の作業は省略できません。

認証情報を変える

攻撃者がパスワードや設定ファイルの中身を盗んでいる前提で、すべて変更します。

# 認証用キーとソルトを作り直す(全ユーザーがログアウトされる)
wp config shuffle-salts

# 管理者全員のパスワードをリセットし、本人にメールで通知
wp user reset-password $(wp user list --role=administrator --field=ID)

WordPressの外側の認証情報も変更します。

  • データベースのパスワード(変えたら wp-config.php の DB_PASSWORD も合わせる)
  • SSH・SFTP・FTPのパスワードと公開鍵の一覧
  • ホスティングの管理画面のパスワード
  • wp-config.php やプラグインの設定に入っている外部サービスのAPIキー

再侵入を防ぐ設定

uploads でPHPを実行させない

uploadsに置かれたPHPが実行されなければ、アップロード経由のバックドアは動きません。Apache 2.4 では、wp-content/uploads/.htaccess に次のように書きます(サーバー側の AllowOverride で上書きが許可されている必要があります)。

<FilesMatch "\.(php|phtml|phar)$">
    Require all denied
</FilesMatch>

Nginx では、サーバー設定の location ~ \.php$ より前に次のブロックを置きます。正規表現の location は書いた順に評価されるためです。

location ~* ^/wp-content/uploads/.*\.(php|phtml|phar)$ {
    deny all;
}

管理画面からのファイル編集を止める

管理者アカウントを乗っ取られたときに、テーマやプラグインのファイルを管理画面から書き換えられないようにします。wp-config.php の「編集が必要なのはここまで」の行より上に追加します。

define( 'DISALLOW_FILE_EDIT', true );

パーミッションを標準に戻す

ディレクトリは755、ファイルは644が基本です。再帰的に chmod 755 を実行すると、ファイルにも実行権が付いてしまうので、ディレクトリとファイルを分けて設定します。

find /var/www/html -type d -exec chmod 755 {} +
find /var/www/html -type f -exec chmod 644 {} +

定期的に照合する

チェックサムの照合は数秒で終わるので、cronで毎日実行し、結果に警告があればメールで知らせるようにしておくと、次の改ざんに早く気づけます。

# crontab -e で登録する例(毎日4時)
0 4 * * * cd /var/www/html && wp core verify-checksums --include-root 2>&1 | grep -q Warning && echo "checksum warning" | mail -s "WP checksum" admin@example.com

mail コマンドが使えるかどうかはサーバーの構成によります。

作業後の確認

  • wp maintenance-mode deactivate でメンテナンス画面を解除し、表と管理画面の表示を確認する
  • Google Search Console の「セキュリティの問題」レポートに警告が出ていれば、対処内容を書いて審査を依頼する
  • 数日から数週間は、アクセスログとファイルの変更を続けて監視する

まとめ

  • バックドアが残っていると、表の改ざんを消しても再発する。調査前にファイル・DB・ログを保存する
  • wp core verify-checksums --include-root と wp plugin verify-checksums --all で、公式配布物との違いを洗い出す
  • uploads内のPHP、mu-plugins、ドロップイン、.htaccess・.user.ini の auto_prepend_file を目で確認する
  • データベースの管理者ユーザーと予約処理、アクセスログのPOSTも調べる
  • 除去は公式ファイルでの上書きと不要ファイルの削除。その後ソルトとパスワードをすべて変える
  • uploadsでのPHP実行禁止、DISALLOW_FILE_EDIT、755/644、定期的な照合で再侵入を防ぐ

関連記事:

お気軽にご相談ください

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