あるWordPressサイトで、TOPページにアクセスすると違うサイトに飛んでしまう
管理画面は致命的なエラーで開けない
サーバー内に見覚えのないPHPファイルが大量にある
Googleに怪しいURLが大量にインデックスされている
え、なにこれ…
この記事では、そんな状態から私が実際に確認したこと、復旧のために行った対応、対応後に監視したことをまとめます。
※この記事は、セキュリティ専門業者による本格的な調査ではなく、フリーランスのWeb制作者として実際に確認した内容の記録です。
※実際のドメイン名、不審URL、ファイル名、DB名などは伏せています。
まず最初に:確認できた異常
今回対応したのは、しばらく更新されていなかったWordPressサイトです。
最初は、WordPressの致命的エラーやPHPバージョンの問題かな?と思っていたのですが、調べていくうちに
- TOPページにアクセスすると別のショッピングサイトにリダイレクトされる
- Google検索結果に見覚えのないURLが出ている
- サイト内に本来存在しないはずのURLがある
- サーバー内に怪しいPHPファイルがある
ということが分かってきました。
サーチコンソール(Google Search Console)でも以下のような異常が確認できました。
ウェブ検索の合計クリック数が不自然に増加していた

4月末頃から、突然クリック数が増えています。(5月末に対応し、その後は通常の数に戻っています。)
身に覚えのないインデックス登録の増加

4月末から急激にインデックスされるページが増えています。
インデックス追加されているページも以下のとおり、「ドメイン/?n=xxxxx」という不審な形です。
大半がショッピング系サイトへアクセスされるようになっていました。

サーバーのアクセスログにも、攻撃の形跡がたくさん…


急激にアクセスが増えすぎてて怖い…
これはただの不具合ではなく、ほぼ確実にマルウェア感染やSEOスパムだよね…
※マルウェア:サイトやサーバーに悪さをする不正なプログラムのことです。WordPressの場合、不審なファイルを置かれたり、ページを書き換えられたり、別のサイトへ誘導されたりすることがあります。
※SEOスパム:検索結果を悪用する目的で、サイト内に見覚えのないページやリンクを勝手に作られてしまうような被害のことです。ショッピング系・海外サイト系・ギャンブル系など、サイト本来の内容とは関係ないページがGoogleに表示されることがあります。
すぐに以下の順番で確認していきました。
サーバー上の不審ファイルを確認
まずは、サーバー上のファイルを確認しました。
WordPressのコアファイル、テーマ、プラグイン以外に、見覚えのないPHPファイルがないかをチェックしました。
すると出るわ出るわ大量の不審ファイル。
もれなく全ディレクトリに.htaccess が作成されていて思わず声が出ました。
中でも今回特に怪しいと感じたのは、ファイルマネージャー系のPHPファイルです。
中身を確認すると、
- ファイルマネージャーの認証を使わずに操作できる設定
- ドキュメントルート配下のファイルを操作できる設定
- WordPressとは関係なさそうな処理
が実装されているものでした。
通常のWordPress運用で、public_html直下にこのようなファイルが必要になることはほとんどないと思います。
というか見慣れなさすぎて違和感しかありませんでした。
よって、発見した不審なファイルはバックドアやWebシェルとして悪用される可能性があるファイルとして調査を続けました。
※バックドア:通常のログイン画面とは別に、攻撃者があとから再び侵入できるように残しておく「裏口」のようなものです。
※Webシェル:ブラウザ経由でサーバー上のファイルを操作したり、コマンドを実行したりできる不正なプログラムのことです。
DB内の改ざんも確認
次に、データベース内も確認しました。
感染ファイルだけ削除しても、DB内に不審なコードやURLが残っていると、また怪しい表示やリダイレクトが発生する可能性があります。
確認したキーワードや内容は、たとえば以下のようなものです。
- base64_decode
- eval(
- gzinflate
- script
- iframe
- 不審なドメインやユーザーが追加されていないか
なぜこれらのキーワードを確認したか知りたい人はこちら
- 「base64_decode」
Base64形式で隠された文字列を元に戻すPHP関数です。マルウェアでは、悪意のあるコードをそのまま書くと見つかりやすいため、Base64形式に変換して隠している場合があります。特に、意味の分からない長い英数字の文字列と一緒に使われている場合は注意が必要です。 - 「eval(」
文字列をPHPコードとして実行する関数です。DB内や外部から取得した文字列をそのままPHPコードとして実行できてしまうため、悪用されるとかなり危険です。特に、eval(base64_decode(…)) のように、隠したコードを復元して実行する形で使われている場合は注意が必要です。 - 「gzinflate」
圧縮されたデータを元に戻すPHP関数です。マルウェアでは、悪意のあるコードを圧縮して隠しておき、実行時に展開するために使われることがあります。特に、eval(gzinflate(base64_decode(…))) のように、base64_decode や eval と組み合わせて使われている場合は注意が必要です。 - 「script」
JavaScriptを読み込んだり実行したりするためのHTMLタグです。通常のサイトでも使われるため、script があるだけで危険というわけではありません。ただし、見覚えのない外部URLを読み込む script タグがDB内に入っている場合、不正なリダイレクトやスパム表示に使われている可能性があります。 - 「iframe」
ページ内に別のページを埋め込むためのHTMLタグです。YouTube動画やGoogleマップの埋め込みでも使われるため、iframe 自体が悪いわけではありません。ただし、見覚えのない外部サイトを読み込む iframe がDB内に入っている場合、スパムページや不正な広告表示に使われている可能性があります。
確認した範囲では、DB内に明らかなマルウェアコードや不審ドメインの痕跡は見つかりませんでした。
よって、DB内のデータはそのまま使う方針にしました。
バックアップをそのまま戻すのは危険
ファイルは感染済み、DBは感染していなさそう、ということが分かったところで、まずサーバー側で自動取得されていたバックアップをリストアすることを考えました。
が、バックアップを確認してみてびっくり。
一番古い日付のバックアップも含め、公開ディレクトリ内のファイルがすべてマルウェア感染済みの状態でした。
幸い、構築当初のテーマファイルのみ、別の場所にバックアップされていました。
(これがなかったら復旧は無理だったと思います…)
そのため、今回の復旧計画は以下のとおりとしました。
- 感染時期が分からないバックアップを丸ごと戻すことはしない
- WordPress本体は新たにクリーンなものを入れ直す
- テーマは別の場所に保管してあったものを使用する
- プラグインは必要なものだけ入れ直す
- DBは問題なさそうなのでそのまま使う
バックアップがあるから安心!ではなく、
そのバックアップが安全な状態なのか?を確認することが大切です!!
実は最初に異常が見つかったサイト以外にもサブディレクトリで運用されているブログが2つあり、合計3つをほぼ同じ手順で復旧することになりました…
まずバックアップ、そして全削除、再インストール
まず、以下のとおり作業を進めました。
- DBダンプ取得
- ファイルバックアップ
(テーマの内容などを確認するため、念のためバックアップを取得し別の場所に保存しておきました) - 感染ファイルを残さないため、公開領域内の全ファイルを削除
- WordPress簡単インストールを使いたいので、DBもすべて削除
- WordPress簡単インストール機能で、WordPressを再インストール
(ここでDBも再作成されます) - 別の場所に保存してあったテーマファイルを復元
- 新WordPressのDBに、バックアップしたDBダンプからデータ復元
ここまでで、Webサイト自体は正常に表示できるようになっていました。
でも今回はこれだけでは終わりません。
- 再感染を防止するため
- 不正URLがインデックス登録されている問題を解決するため
さらに以下の対応を実施していきました。
ID、パスワードを変更
まずは基本的な対応として、各種認証情報を変更しました。
今回の感染経路を完全に特定できているわけではないため、念のため、以前のログイン情報は使い続けない方が安全だと判断したからです。
変更したのは、以下のようなものです。
- WordPressの全ユーザーID・パスワード
(管理者権限のものだけで良かったかもしれませんが、念のため) - FTPアカウントのID、パスワード
- サーバー管理画面のパスワード
- データベースの接続情報
マルウェア対応では、不審ファイルを削除してサイトを復旧するだけでなく、再度侵入される可能性を減らすことも大切だと思います。
認証情報が漏れていた場合、苦労して復旧してもまた不正なファイルを作られてしまい、イタチごっこになる可能性があるからです。
そのため、復旧作業とあわせて、関連する認証情報も変更しておきましょう!
.htaccessで410 Gone対応
不正URLに対しては、.htaccess で直接 410 Gone を返す対応を行いました。
よく見かける 404 Not Found は「ページが見つからない」という意味です。
対して、410 Gone は「そのページは削除され、今後も戻る予定がない」という意味です。
今回は、Googleに残っていた不正URLを早めに削除対象として認識してもらうため、不正URLっぽいものには 410 Gone を返すようにしました。
一方で、アクセスさせたくないURLには 403 Forbidden を返すなど、目的に応じてステータスコードを分けています。
対応後は curl コマンドで、以下のような項目を確認しました。
- 不審URLが410 Goneになっているか
- リダイレクト後に最終的に410 Goneになっているか
- 通常ページに影響が出ていないか
- サイトマップが正常に表示されているか
.htaccess は書き方を間違えると、正常なページまで表示できなくなることがあります。
必ず検証した上で本番適用しましょう!
サイトマップも確認
あわせて、サーチコンソールへサイトマップを再登録しました。
今回も、実際にサイトマップURLへアクセスして、
- 正常に200 OKが返っているか
- 不正URLが含まれていないか
を確認しました。
※本対応は、マルウェア対応として必須のものではないと考えています。
※今回はインデックスに影響があったことやWordPress内でサイトマップを出力するプラグインを使用していたため、念のため実施しました。
対応後も数日監視
対応を行った後は、すぐに「これで完全に解決!」とは判断せず、数日間監視することにしました。
マルウェアやSEOスパムの場合、怪しいファイルを削除したあとに、別の場所から再生成される可能性もあります。
また、Google検索結果に残っている不正URLも、対応してすぐに消えるわけではありません。
そのため、対応後は数日間、以下のような点を確認しました。
・不審なPHPファイルが再生成されていないか
・不正URLにアクセスしたとき、想定どおり 410 Gone や 403 Forbidden が返っているか
・通常ページが問題なく表示されているか
・サイトマップが正常に表示されているか
・サーチコンソール上で新たな不審URLが増えていないか
・Google検索結果に怪しいページが残っていないか
特に、不審ファイルの再生成がないかは注意して見ました。
一度削除して終わりではなく、数日間は「また出てきていないか」「別の場所に怪しいファイルがないか」を確認した方が安心だと思います。
今回も、対応後しばらく監視しながら、通常ページやサイトマップに影響が出ていないかもあわせて確認しました。
今回確認・対応したことまとめ
今回、私が確認・対応したことは以下です。
- WordPressの致命的エラーを確認
- PHPバージョン起因の不具合ではなさそうだと判断
- TOPページから別ショッピングサイトへリダイレクトされることを確認
- Google検索結果に見覚えのないURLが出ていることを確認
- サーチコンソールでクリック数・インデックス数の不自然な増加を確認
- サーバーのアクセスログで不審なアクセス増加を確認
- サーバー上の不審なPHPファイルを確認
- ファイルマネージャー系の怪しいPHPファイルを確認
- DB内に不審なコードや外部URLがないか確認
- 不審なユーザーやドメインが追加されていないか確認
- サーバー側のバックアップも感染済みだったため、丸ごとリストアは危険だと判断
- DBダンプとファイルバックアップを取得
- 感染ファイルを残さないため、公開領域内のファイルを全削除
- WordPressをクリーンな状態で再インストール
- 別の場所に保存されていたテーマを復元
- 必要なプラグインのみ入れ直し
- DBダンプからデータを復元
- 不正URLに対して .htaccess で 410 Gone を返す対応を実施
- アクセスさせたくないURLには 403 Forbidden を返すように設定
- curl コマンドでステータスコードを確認
- 通常ページに影響が出ていないか確認
- サイトマップの状態を確認
- サーチコンソールへサイトマップを再登録
- 対応後も数日間、不審ファイルの再生成や不正URLの増加がないか監視
多い、、、!(しかもこれを3サイト分)
最初はすごく焦りましたが、順番に確認していくことで、
- どこが感染していそうか
- どこが問題なさそうか
- 何を戻して良くて、何を戻してはいけないか
- Google側に残っている不正URLへどう対応するか
が少しずつ見えてきました。
特に今回は、サーバー側のバックアップまで感染済みだったため、「バックアップがある=すぐ戻せる」というわけではないことを痛感しました。
バックアップがあるかどうかだけでなく、そのバックアップが安全な状態なのか?まで確認することが大切です。
今後やっておきたいこと
今回の件を踏まえて、今後マルウェア感染を防ぐため以下の対応をしておくのが良さそうです。
- WordPress本体、テーマ、プラグインを定期的に更新する
- 使っていないテーマ、プラグインは削除する
- 不要なPHPファイルが公開領域に残っていないか確認する
- 管理者ユーザーを定期的に見直す
- 強いパスワードと二段階認証を設定する
- 定期バックアップを設定する
- バックアップは複数世代残す
- サーバー内だけでなく、外部ストレージにもバックアップを保存する
- バックアップから実際に復元できるか確認する
- サーチコンソールも定期的に確認する
- インデックス数やクリック数が急に増えていないか確認する
- アクセスログに不審な急増がないか確認する
バックアップは「取っているつもり」ではなく、実際に安全な状態で残っているか、復元できるかが大事です!
また、WordPress本体やプラグインの更新だけでなく、使っていないファイルを放置しないことも大切だと感じました。
不要なファイルが残っていると、そこが攻撃の入口になる可能性もあります。
今回のサイトはコストの問題で定期保守はされていませんでした。
ダウンタイムが発生しても問題ないとのことで、今回のように問題が起きてから対応する方針となっているようです。
最後に
ここまで、WordPressサイトでマルウェア感染が疑われた場合に実施した対応について紹介しました!
今回は、怪しいファイルを削除するだけでは不十分で、サーバー上の不審ファイル、DB、バックアップ、不正URL、サーチコンソールまわりを順番に確認しながら対応していきました。
特に、バックアップが感染済みだったことから、「バックアップがある=安全に戻せる」とは限らないことを痛感しました。
対応後すぐに安心せず、数日間は不審ファイルの再生成や不正URLの増加がないか確認することも大切だと感じています。
同じように、WordPressサイトのマルウェア感染やSEOスパムで困っている方や、どのような対応をしたか興味がある方のご参考になれば幸いです!

