【2026年最新】WordPressマルウェアの対応、乗っ取り復旧方法と手順の完全ガイド|プロが教える

概論

バックアップが利用できることを前提に、WordPressのマルウェア感染や乗っ取り被害から復旧する具体的な方法と手順を解説します。
AIで手順を調べることはできますが、実際の復旧には最低限の基礎知識と道具が必要です。本記事では、実務の観点から、WordPressのマルウェア感染・乗っ取り被害の復旧手順を解説していきます。

WordPressの復旧では、ファイルをクリーンに入れ替えても、コア・プラグイン・テーマ・PHPの互換性によって問題が発生することがあります。特に古いサイトでは影響が出やすく、最新版への更新が望ましいものの、状況によっては段階的な対応が必要です。
また、感染状況やサーバー環境によって手順は変わるため、乗っ取り復旧は一律ではなく、状況に応じて進める必要があります。

記事の対象者

この記事は、バックアップが利用できることを前提に、WordPressのマルウェア感染・乗っ取り被害を復旧したい方向けに書いています。具体的には次の方になります。

  • WordPressの基本構成を理解している方
  • FTP/SFTPソフトでファイル操作ができる方
  • バックアップの復元やファイルの退避・入れ替えができる方

バックアップがない方、停止リスクの大きいサイトを運営している方は、自力対応ではなく専門業者への依頼を検討してください。

自力での復旧をおすすめしない人

FTP/SFTPの操作経験がない方、バックアップがない方、また、FTP/SFTPの操作経験があってもサーバーやWordPressの基本構成がわからない方、ECサイト・会員サイト・予約サイトなど停止や誤操作の影響が大きいサイトを運営している方には、自力での復旧をおすすめしません。初心者は非推奨です。データを壊すリスクが高いです。

復旧のスピードを重視する方

早期復旧を優先したい場合は、専門業者への依頼を検討してください。本記事の内容を理解しておくことで、復旧業者とのやり取りがスムーズになり、無駄な調査時間やコストを減らせる可能性があります。

WordPress乗っ取り復旧の全体フロー

本記事の復旧は、次の流れで進めます。

  1. パスワードの変更
    サーバー・FTP/SFTP・WordPressの認証情報を先に変更し、被害の拡大を防ぐ
  2. アクセス遮断(503)
    .htaccessで自分以外のアクセスを遮断し、攻撃を一時停止させる
  3. バックアップからデータを戻す
    可能な限り過去の状態へ戻すが、「治ったように見える前提」で進める
  4. 感染状況のチェック
    転送・管理画面・ファイル状態などから、感染の残存を確認する
  5. WordPressコアの入替え
    上書きではなく、ディレクトリ単位でクリーンな状態へ入れ替える
  6. wp-contentの復旧
    プラグイン・languages・権限などを整理し、不正ファイルを排除する
  7. DB・uploadsの確認
    データベースとアップロード領域に残る不正要素をチェックする
  8. Wordfenceで最終確認
    スキャンで取りこぼしや残留マルウェアを確認する

WordPress乗っ取り復旧の初動対応

パスワード類は先に変更 ・サーバーログイン、FTP/SFTP、WordPressログインのパスワードを先に変更します。
WordPressのマルウェアによる乗っ取りでは、リダイレクトの原因が必ずしもログイン情報の流出とは限りません。ですが、対応としては必ずやってください。
管理権限が脆弱性を突かれて奪われることと、管理者アカウントのパスワード自体が物理的に漏れていることは別問題です。ここは切り分けて考える必要があります。

一旦アクセスを遮断します。

.htaccess に、自分のIPアドレス以外を通さない記述を入れます。
完全遮断はプラグインではできません。WordPressプラグインはPHP実行後に動くため、WordPressを経由しないマルウェア(直接PHP実行、既設バックドア、静的ファイル経由など)は簡単にすり抜けます。
自分のIPアドレスは、「確認くん」などで確認できます。
https://www.ugtop.com/spill.shtml
表示される「あなたのIPアドレス(IPv4)」が使うIPアドレスです。

メンテナンス用のmaintenance.htmlを作成し、アップロードしておきます。ChatGPTなどを使う場合は、個人情報を入力せず、空欄のまま作成してローカルで編集してください。
<プロンプト>
メンテナンス中のmaintenance.htmlを作ってほしい。必要なことをあなたが質問して。それを元に生成してください。

maintenance.html をルートに置いておけば、自分以外にはメンテナンスページを見せつつ、HTTP ステータスは 503 になります。

一時的にアクセスを遮断する

ErrorDocument 503 /maintenance.html
RewriteEngine On 
# 自分のIPは通す
RewriteCond %{REMOTE_ADDR} !^xxx\.xxx\.xxx\.xxx$
# メンテナンスページ自体は通す
RewriteCond %{REQUEST_URI} !^/maintenance\.html$
# それ以外は503を返す
RewriteRule ^ - [R=503,L]

.htaccess で自分の IP 以外を遮断し、外部からのアクセスを一時停止します。このとき、302 リダイレクトではなく 503 Service Unavailable を返す 形にしておくと、メンテナンス中であることを検索エンジンに正しく伝えやすくなります。Google も、計画停止や一時的なオフライン対応では 503 を返す方法を案内しています。
参考URL: https://developers.google.com/search/blog/2011/01/how-to-deal-with-planned-site-downtime
参考URL: https://developers.google.com/search/blog/2008/04/my-sites-been-hacked-now-what

※ 192.168.0.x 、10.x.x.x 、172.16.x.x はここで使うIPアドレスではありません。これらはローカルIPアドレスで、電話でいうと内線番号のようなものです。

メンテナンスモードでは不十分

WordPressのメンテナンスモードは、「.maintenance」ファイルを配置して表示を変える方法、またはプラグインでメンテナンス中の画面を表示する方法を指すことが一般的です。
ただ、これはあくまで表示上の問題です。サイトを完全に外部から遮断したことにはならない場合が多いです。

サイトを完全に遮断しない限り、攻撃は止まりません。普通に来ます。表示上はメンテナンス中にしていても、裏では攻撃が続いていることは普通にあります。
マルウェアやボット(自動化された攻撃プログラム)は、たとえば次のような場所を攻撃してきます。

攻撃対象になりやすいポイント

ログイン系
/wp-login.php
API系
/xmlrpc.php
非同期処理
/wp-admin/admin-ajax.php
不正実行
バックドア / cron
設定改ざん
.user.ini 注入
いくらでも攻撃してきます。だからこそ、まずは「見せ方」ではなく「遮断」を優先します。

バックアップからデータを戻す

バックアップから戻して症状が治る場合があります。ただし、「治る」のと「治っているように見える」のは雲泥の差です。
我々からすると、バックアップ復元は復旧のスピードを少し早める程度の意味合いです。しかし一般的には、管理画面に入れるようになっただけで自己復旧したように見えます。

ここは、「治っているように見える」前提で復旧作業を進めるくらいでちょうどいいです。
運営者の都合にもよりますが、できるだけ前のバックアップに戻すことが重要です。WordPressのマルウェアは、いつ入り込んでいるのか分からないことが多いからです。

弊社にご依頼されるお客様でも、2年前のバックドアの痕跡が出てきた事例があります。これは、偽装できるタイムスタンプを見たのではなく、時系列の矛盾から弾き出した結果です。
バックアップは、プラグインで取得したもの、またはサーバー会社のバックアップから戻すことを想定しています。

サーバー会社のバックアップ機能について

本筋からは少し外れますが、サーバー会社のバックアップ機能は非常に重要です。サイト運営者にとってはかなり心強い存在ですし、WordPressを運用する上ではサーバー選定の大きな判断材料にもなります。特に乗っ取り被害時には、その効果が大きく出ます。

ただし、1台のサーバーにWordPressを載せすぎると、容量の問題でバックアップが取得できないことがあります。コスト面では合理的でも、1サイトの感染が全体に広がるケースを多く見てきました。
復旧には時間も費用もかかりますし、担当者の精神的な負担もかなり大きくなります。

【デバッグポイント】マルウェア感染チェックリスト

次の項目は、「感染していない確認」ではなく、「まだ復旧途中、または感染が残っている可能性があるか」を見るチェックポイントです。ここで問題が出るようであれば、バックアップから戻しただけでは足りない可能性があります。

  • 管理画面にログインできて、デザインが崩れていない
  • 何かしらのプラグインをインストールできる
  • 転送されない
  • index.php や .htaccess が汚染されていない
  • 新規投稿画面が問題なく開き、テストで下書きできる
  • プラグインの新規追加で、何でもよいので検索ができる
  • ユーザー一覧に不審なユーザーがいない
  • 管理画面上部に英語のエラーメッセージが表示されていない

index.php や .htaccess の内容が分からない場合は、ファイルをコピーしてChatGPTに投げて確認する方法もあります。ただし、顧客情報・認証情報・個人情報は入れないでください。
また、AIから復旧手順を提示された場合も、そのまま実行せず、かなり慎重に判断してください。

転送確認は、次の方法で行います。

  • シークレットモードで確認する
  • 閲覧履歴とクッキーを削除できるブラウザで確認する
  • スマホでWi-Fiを使わず、シークレットモードで検索して確認する

※必要であれば、自分のIPアドレスを .htaccess に追加してください。

ここが、ひとつの基準です。
そもそもWordPressの管理画面が真っ白、403が出るという状態だと、バックアップ自体がすでにマルウェアにやられている可能性がかなり高いです。この場合、バックアップから戻すだけでの復旧は厳しいです。

転送は人を見て出し分けるマルウェアがある

転送系のマルウェアは、全員を同じ条件で飛ばすとは限りません。ここを誤解すると、管理者本人が確認したときに転送されず、「治った」と誤認します。

このパターンは、2年くらい前まではかなり典型的でした。最近は少し減ってきた印象はありますが、いまでもメジャーな手口のひとつです。
実際には、IPアドレス、リファラー、Cookie、ログイン状態、User-Agent、アクセス元、時間帯などを見て条件分岐し、管理者や調査者には転送させず、一般ユーザーにだけ転送するような挙動を取ります。

たとえば、次のような条件で挙動を変えるマルウェアがあります。

  • 管理画面にログインしているアクセスは除外
  • WordPressの認証Cookieを持っているアクセスは除外
  • 管理者が普段使うIPアドレス帯は除外
  • Google検索、広告、外部サイト経由の流入だけを対象にする
  • スマホ系のアクセスだけを対象にする
  • 一定時間ごと、または確率でだけ発火する

この手の個体は、管理者本人のPCでは再現しないことがあります。そのため、転送確認は自分のブラウザだけで終わらせてはいけません。シークレットモード、別ブラウザ、スマホ回線、別端末での確認が必要です。

※弊社ののマルウェアサンプルは確認していますが、悪用防止のため、ここでは実行可能なコードは掲載せず、挙動が分かるよう無毒化・一部改変した内容で説明します。

【弊社のマルウェアサンプル】から抜粋(無毒化・一部改変)

スクリプトを解析すると、概ね下記のような条件分岐になります。

  • 管理者としてログインしているアクセスは除外する
  • WordPressの認証Cookieを持っているアクセスは除外する
  • 管理者が普段使っているIPアドレス帯からのアクセスは除外する
  • bot、crawler、scannerと判定したアクセスは除外する

次の条件がそろったときだけ、転送または外部読込を行うという作りです。

  • 一般ユーザーのアクセスである
  • 検索エンジン、広告、外部サイト経由のアクセスである
  • スマホ系のアクセスである
  • 管理画面やログイン画面へのアクセスではない
  • すでに処理済みであることを示すCookieを持っていない

実際の不正コードは文字列を分割したり、難読化したり、外部ファイルを読み込んだり、条件を増やしたりして、ぱっと見では分からないようにしてあります。
そのため、コードを1回見ただけでは「転送先が見えない」「何もしていないように見える」ことも珍しくありません。

ここで重要なのは、自分では転送されない = 感染していない、ではないという点です。なので管理者は中々気付かず、「お客様から指摘があって気づいた」というご依頼者は少なくありません。
いつものPC、いつもの回線、ログイン済みのブラウザで確認すると、普通に表示されて「治った」ように見える。しかし実際には、検索結果や外部サイトから来た一般ユーザーにだけ転送している、ということがあります。
だからこそ、復旧確認は「自分で見て問題なかった」ではなく、「条件を変えても再現しない」まで見る必要があります。

マルウェア感染を強く疑うチェック

過去の事例から見ても、かなりの確率で感染を疑うべきチェックポイントがあります。ここでいうのは、感染していないことを確認するチェックではなく、感染している可能性が高いチェックです。

1・直下の .htaccess が不自然

多くのWordPress環境では、公式が示す基本形として「 # BEGIN WordPress と # END WordPress」 を含む .htaccess が使われます。
そのため、直下の .htaccess が極端に短く、下記のような記述しかない場合は不自然です。
https://developer.wordpress.org/advanced-administration/server/web-server/httpd/

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /

RewriteRule ^index\.php$ - [L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

もちろん、これだけで感染確定とは言えません。ただ、実務上はこの記述がサーバー内へ大量にばらまかれている事例があります。
多いときは、6,400ファイル以上作られていたケースもありました。報告書を見て依頼主様はかなり驚かれますが、こういうファイルは本当に秒で増えます。

2・/uploads/ 直下の .htaccess が不自然

/uploads/ は本来、画像やPDFなどのアップロードファイルを置く場所です。
ここに php5 や php7 など、PHP実行まわりの文字が不自然に並んでいる場合は典型的なパターンです。かなり強く疑います。

3・public_html 配下のアクセス権を確認する

弊社では、public_html 配下のパーミッションがどうなっているかを一度チェックします。
このパターンは、実務でもよく見かけます。

特に、444 や 555 になっているファイルやディレクトリがある場合は要注意です。
フォルダのアクセス権が 555 になっていると、その配下のファイルやディレクトリを通常の操作で削除できないことがあります。
444 や 555 は、マルウェアが自分を消されにくくするために、意図的に権限を固めている典型例として見かけます。かなり強く疑うべき状態です。

たとえば、SSHで次のように確認します。

find ./ -perm 555 > 555.txt
find ./ -perm 444 > 444.txt

※SSHでの作業になります。コマンドを実行する際は、カレントディレクトリが public_html (または公開ディレクトリ)であることを必ず確認してください。

4・全ページがトップページと同じで、管理画面に入れない

一見すると、単なるWordPressの設定ミスのように見えることがあります。
ただ、このパターンはかなり厄介です。専門業者へ即依頼をすすめます。

このタイプは、ゾンビのようにマルウェアが再生成されることがあります。サーバー内に入っているWordPressをすべて一度アクセス禁止にし、1つずつ対処していく必要が出ることもあります。
マルウェアの復旧は、本来こうあるべきです。ただ、実務ではスピードも求められるので、そうも言っていられない場合があります。弊社でも数人で5WordPressを同時進行するのは普通にあります。ですが、このパターンは同時進行が通用しません。

サーバーの中身は、一見すると普通のWordPressのディレクトリやファイル名です。
しかし中身は、トップページだけを表示するためのスカスカなファイルになっていて、裏ではマルウェアが動いています。これもアウトです。

5・Search Console で確認する

Search Console の「セキュリティと手動による対策」に、セキュリティの問題や手動による対策が表示されていないか確認します。
ただし、ここは時差があります。 表示がないから安全とは限りません。
https://developers.google.com/search/docs/monitor-debug/security/prevent-malware

サイトを閉鎖したのに転送される、おかしな挙動をする?

これは、WordPressの実行領域の話になります。
WordPressは立ち上がる段階で、必ず複数のファイルを順番に読み込みます。ここでいう「立ち上がる」とは、表示処理が開始される状態です。
その読み込みの流れのどこかにマルウェアが仕込まれていると、サイトを閉鎖したつもりでも、自分のIPアドレスでアクセスした瞬間にWordPress自体が起動し、マルウェアも一緒に動きます。

ざっくり言うと、ファイルの読み込みの流れは次のようになります。

index.php
→ wp-blog-header.php
→ wp-load.php
→ wp-config.php
→ wp-settings.php
→ wp-includes/ 配下の各種ファイル

この読み込みの流れにフックして動くマルウェアは、実務上かなり多いです。
復旧では、まずこの流れのどこで不正な処理が差し込まれているかを疑って見ます。wp-settings.php はWordPressの初期化処理を担うコアファイルで、読み込みの起点として重要です。
https://developer.wordpress.org/reference/files/wp-settings.php/

基本的に、こうしたマルウェアは HTTPリクエスト(Webアクセス) のような「トリガー」がないと実行されません。ここが、Windowsの常駐型マルウェアとは違うところです。
そのため、サイトを封鎖しても、自分のIPアドレスを許可してアクセスすればWordPressは起動します。
つまり、マルウェアも動きます。ただし、それでもサイトを封鎖する意味は大きいです。被害を最低限に抑えるという意味では、かなり重要です。

この時点で「もう詰みでは?」という話になりがちですが、まだ進められます。
このあと最後まで、問題を1つずつ潰していきます。

/wp-content/mu-plugins/ のチェック

ここは、プラグイン一覧に出てこない特殊なプラグインを置く場所です。
WordPressの仕組み上、通常のプラグインより先に読み込まれるため、マルウェアを仕掛けるにはかなり都合のよい場所です。まず疑ってチェックします。

確認場所は次です。
管理画面 > ツール > サイトヘルス > 情報タブ > MUプラグイン

ここも、内容が分からなければファイルをコピーしてChatGPTに投げてみてもよいです。
ただし、認証情報や個人情報は入れないでください。
正直、私も一見しただけでは判断がつかないことがあります。ただ、視認レベルでも結構見つかります。
とはいえ、ここに何もなかったから安心、とは全く言えません。複数箇所に仕込まれていることは普通にあります。

/wp-content/plugins/ のチェック

plugins フォルダの中の数と、サイトヘルスで見えるプラグイン数が合っているか確認します。
実務では、plugins.php のように、一見すると当たり前に見える名前で紛れていることがあります。こういうのを見ます。

確認場所は次です。
管理画面 > ツール > サイトヘルス > 情報タブ
・使用中のプラグイン
・停止中のプラグイン
※情報をコピーできるポタンがあるので、コピーしてファイルに保存することを強くお勧めします。途中で管理画面に入れなくなったときは、貴重な情報になります。

フォルダにある数と、管理画面上で認識されている数が合わない場合は、かなり注意です。
見えていないファイル、見えていないプラグイン、そもそもWordPressの管理画面に出てこない細工が入っている可能性があります。

ファイルの入替え

ここから、実際にファイルの入替えを行っていきます。
その前に、復旧で必要になる前提知識を書きます。そんなのはいらないから、さっさと答えを教えてほしいという方もいるでしょう。

ですが、ここをある程度理解しないと、WordPressは普通に壊れます。
表現が正しいかどうかはさておき、エンジニアの成長のひとつは、やらかした数と真っ青になった数です。そうやって経験と判断力が上がっていきます。
だからこそ、この前提を抜いたまま復旧すると、うまくいかないリスクが上がります。私自身、昔は相当このような青ざめた経験はありました。(いまもありけど)

ファイルの入替えは不可避

WordPressコアの入替えと、プラグインの入替えは不可避です。ここは強く言います。不可避です。

理由は単純で、コアファイルを上書きしただけでは、マルウェアが独自に作成したファイルやディレクトリは消えないからです。
WordPress本体の正規ファイルが新しくなっても、正規ファイル名ではない不正ファイル、あとから追加されたバックドア、別ディレクトリに置かれた不正コードはそのまま残ります。

つまり、上書きでは「見えているファイル」は新しくなっても、見えていない不正ファイルは残るということです。
だから、一度ディレクトリを空にしてから、クリーンなファイルを配置する必要があります。
これが、コアファイルの総入替えを断定できる理由です。

アップデートすれば入れ替わるのでは?

ここでよく出るのが、「アップデートすれば入れ替わるのでは?」という話です。
ですが、復旧の観点ではそれでは足りません。

WordPressコアファイルは?
→ 上書きでは、マルウェアが追加した独自ファイルや独自ディレクトリが残存する可能性があります。

そもそも、コアファイル名以外の不正ファイルがあれば、アップデートでは消えません。ここはかなり見落とされがちです。
だから、まるごと入れ替える必要があります。 上書きでは意味がありません。あくまで入替えです。

PROFESSIONAL-POINT
WP-CLIでの再取得も、考え方としては同じです。

wp core download --force

これでコアファイル自体は再取得できます。ですが、すでに追加されている不正ファイルや不正ディレクトリまで消してくれるわけではありません。
復旧として見るなら、これも「上書き」の発想に近く、十分ではありません。

テーマやプラグインは、WordPress標準の更新・インストールの仕組みに沿って処理されます。
この処理は Filesystem API と WP_Upgrader を使って行われ、パッケージの展開、配置先へのコピー、必要に応じた既存ディレクトリのクリアといった流れで進みます。管理画面からの更新だけでなく、ZIPアップロードによるインストールや更新も、基本的にはこの仕組みの上で動いています。
https://developer.wordpress.org/apis/filesystem/
https://developer.wordpress.org/reference/classes/wp_upgrader/

そのため、WordPressの想定する更新・入替えの流れに沿ってテーマやプラグインを入れ替えることには意味があります。
逆に、この仕組みに沿わない中途半端な上書きや、手作業での不完全な差し替えでは、不正ファイルやマルウェアが残る可能性があります。
ここが、単なる「上書き」と「入替え」の違いです。


プラグイン
→ そのプラグインのディレクトリを、クリーンな正規版と入れ替えることで、その配下に仕込まれた不正ファイルは除去できます。

テーマ
→ 親テーマのディレクトリを、クリーンな正規版と入れ替えることで、その配下に仕込まれた不正ファイルは除去できます。

ただし、どちらもそのディレクトリの外にある不正ファイルまでは消えません。だから、やはり全体を見て入替えを考える必要があります。

サーバーのドメイン初期化してリストア

ドメインを初期化して、そこへバックアップを戻して終わり、というのも危険です。
バックアップ自体に不正ファイルが含まれていれば、また同じものを戻すだけになります。入替えは不可避です。

※サーバーの仕様によっては、復元時に wp-content のみ上書きされるケースもあります。この場合は、何が戻されて何が残るのかを確認したうえで判断が必要です。

ワードプレスのフォルダ構成

WordPressのフォルダ構成は、ざっくり言うと wp-config.php と wp-content に個別環境の要素が集まっています。
逆に言えば、それ以外のコアファイルやコアディレクトリは、新品と入れ替える前提で考えやすいです。

つまり、復旧では次のように整理すると分かりやすいです。

  • 残すもの
    ・wp-config.php
    ・wp-content 配下の必要なデータ
  • 入れ替えるもの
    ・WordPressコア一式

単純に入れ替えればいい、という話ではあります。ただし、サイトを止めるかどうか、どの順番でやるか、どこまで先に退避するかは別です。そこは実務判断になります。

wp-config.php は必ずバックアップ

かならずローカルにバックアップを取ってください。
これが消えると、DB接続情報や各種設定を調べ直す必要があり、かなり厄介です。
もちろん、どうにかならないわけではありません。ですが、厄介です。だから、絶対にローカルに保存してください。

wp-config.phpのチェック

-視認によるチェック
wp-config.php は、毎回読み込まれる超重要ファイルです。
ここが汚染されていたら元も子もないので、まずチェックします。

wp-config.php は環境ごとに内容が違うため、標準サイズはありません。
ただ、実務上は 2KB〜6KB 程度に収まっていることが多く、10KB を超えていると不審コード混入を疑うきっかけにはなります。
もちろん、サイズだけで感染確定はできません。あくまで、見るべきサインのひとつです。

正常な wp-config.php では、末尾に次のコメントがあります。

Copy/* That’s all, stop editing! Happy publishing. */
この行より後ろに、意味の分からないコードや不明な処理がぶら下がっている場合は感染を疑います。
また、eval、base64_decode、gzinflate のような文字列が入っている場合も要注意です。
これらが入っているだけで即アウトとは言いませんが、設定ファイルと関係ない複雑なコードや長い文字列があるなら、かなり強く疑います。

SECRET_KEY / SALT のチェック

wp-config.php では、認証キーと SALT の状態も確認します。
ここが初期値のままだと危険です。チェックポイントです。

この状態では、認証キーとソルトが初期値のままなので、ログイン情報の安全性が落ちます。
Cookie やセッションまわりの保護も弱くなり、不正ログインや乗っ取りのリスクが上がります。
WordPress公式でも、Secret Keys と Salts はセキュリティを強化する要素として説明されています。
https://developer.wordpress.org/apis/wp-config-php/
https://api.wordpress.org/secret-key/1.1/salt/

実務では、これが意外と残っています。
私としてはかなり不思議なのですが、お客様にヒアリングすると、WordPressの自動インストール機能がまだそこまで一般的でなかった時代に、ご自身でインストールし、wp-config-sample.php をそのまま使ってしまった、あるいは手動設置のときに置き換えを忘れた、というケースが結構あります。
ここは、かなりの割合で人の設定ミスです。

危険な状態は、たとえば次のようなものです。

define( ‘AUTH_KEY’, ‘put your unique phrase here’ );
define( ‘SECURE_AUTH_KEY’, ‘put your unique phrase here’ );
define( ‘LOGGED_IN_KEY’, ‘put your unique phrase here’ );
define( ‘NONCE_KEY’, ‘put your unique phrase here’ );
define( ‘AUTH_SALT’, ‘put your unique phrase here’ );
define( ‘SECURE_AUTH_SALT’, ‘put your unique phrase here’ );
define( ‘LOGGED_IN_SALT’, ‘put your unique phrase here’ );
define( ‘NONCE_SALT’, ‘put your unique phrase here’ );

この状態であれば、下記へアクセスして表示された値で上書きすれば解消できます。
https://api.wordpress.org/secret-key/1.1/salt/

SALT値の入替え

マルウェア感染や乗っ取り被害に遭った場合、SALT の入替えは「念のため」ではなく、必須の作業です。たとえ初期値から変更されていたとしても、必ず新品に入れ替えてください。

SALT 値を新しく書き換えることで、現在ログインしているすべてのユーザーの接続状態を強制的に切ることができます。
つまり、既存のログインセッションを無効化できます。
対応方法は、前項の値で上書きすればOKです。

デバッグログをONにする

マルウェア感染サイトでは、見えていないエラーや不正挙動がかなり発生しています。

デバッグログを有効化すると、いろいろ見えてきます。もちろん、見えないことに越したことはありません。

ただ、何かで躓いたときには本当に役に立ちます。
私自身も自社でプラグインを作るときは、必ずデバッグを出すようにしています。
WordPress公式でも、WP_DEBUG、WP_DEBUG_LOG、WP_DEBUG_DISPLAY を使ったデバッグ方法が案内されています。
https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/

設定は次のようにします。
/* That’s all, stop editing! Happy publishing. */ より前に入れます。

// デバッグログを有効化(画面には出さない)
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
// PHPのエラー表示を抑制(ユーザーに見せない)
@ini_set( 'display_errors', 0 );
@ini_set( 'display_startup_errors', 0 );


ログは通常、/wp-content/debug.log に出力されます。
ただし、本番サイトで長期間ONにしたまま運用するものではありません。
WordPress公式でも、デバッグ設定は本番よりローカルやステージング向けとされています。
なので、復旧が終わったら必ず OFF に戻します。
https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/

debug.log を外から見えにくくす

ここは少し重要です。
パーミッション設定だけで「外から絶対に見えない」とは言い切れません。
Webサーバーがそのファイルを読める状態なら、HTTP 経由で見えてしまう構成もあるからです。
なので、外部公開を防ぐ対策は、表示禁止設定を優先し、パーミッションは補助として考えるのが安全です。

まず、可能であれば .htaccess などで debug.log への外部アクセスを拒否します。
そのうえで、ファイル権限も絞ります。

WordPress公式のファイル権限の説明では、通常ファイルは 644 / 640、wp-config.php は 440 / 400 が推奨寄りです。
https://developer.wordpress.org/advanced-administration/server/file-permissions/

debug.log については、実務では次のように考えます。

・まず debug.log を生成させる
・内容確認に問題がなければ、可能な範囲で権限を絞る
・所有者やサーバー構成に応じて、600 または 640 を検討する

たとえば SSH なら次のような形です。

chmod 640 /public_html/wp-content/debug.log


さらに絞れる環境であれば、次のようにすることもあります。

chmod 600 /public_html/wp-content/debug.log


ただし、ここは環境依存です。
権限を絞りすぎると、今度は PHP / WordPress 側がログを書けなくなることがあります。
なので、書けることを確認しつつ、可能な範囲で絞るのが実務的です。

加えて、.htaccess が使える環境なら、たとえば次のように debug.log を直接見られないようにしておくと安全です。

復旧後は、
・WP_DEBUG を OFF に戻す
・debug.log を確認して不要なら削除する
・残す場合も外部から見えない状態にしておく
ここまでやって終わりです。

ワードプレスのディレクトリ・ファイル構成
/public_html/

■ ディレクトリ
├── wp-admin/
│ 管理画面一式
├── wp-content/
│ ★テーマ・プラグイン・アップロード
├── wp-includes/
│ コアライブラリ(内部処理)■ ファイル
├── wp-config.php
│ ★最重要:DB接続・セキュリティキー・設定
├── wp-config-sample.php
│ 設定ファイルの雛形(通常未使用)
├── index.php
│ フロント入口(全リクエストの起点)
├── .htaccess
│ URLリライト・アクセス制御(Apache)
├── .user.ini
│ PHP設定上書き(ディレクトリ単位)
│ ・memory / upload制限
│ ・error_log設定
│ ・auto_prepend_file は要注意
├── xmlrpc.php
│ 外部連携API(攻撃対象になりやすい)■ その他コア
├── wp-load.php
│ WordPress起動処理
├── wp-settings.php
│ コア初期化
├── wp-blog-header.php
│ テンプレート読み込み
├── wp-login.php
│ ログイン処理
├── wp-cron.php
│ 疑似cron処理
├── wp-comments-post.php
│ コメント送信
├── wp-signup.php
│ ユーザー登録(マルチサイト)
├── wp-activate.php
│ アカウント有効化
├── wp-mail.php
│ メール投稿処理
├── wp-trackback.php
│ トラックバック処理
├── wp-links-opml.php
│ リンク出力
├── license.txt
│ ライセンス
├── readme.html
│ 説明ファイル

コアファイルの入替え手順

1・ワードプレスのバージョン調査

入れ替えるための WordPress を公式サイトからダウンロードします。同じバージョンを用意するために、まず現在のバージョンを調べます。

確認する場所は /wp-includes/version.php です。
ここには、たとえば $wp_version = ‘6.9.4’; のようにバージョン情報が書かれています。
WordPressが動いているなら、基本的にこのファイルは正しく存在します。
逆に言えば、version.php が正しく存在しないと WordPress はかなり厳しいです。WordPressの仕組み上、このファイルは必ず読み込まれます。

2・ローカルPCで解凍してサーバーにアップ

ここは上書き厳禁です。
上書きしたら意味がありません。WordPressのコアファイルは、まるごと入れ替えないといけません。

作業はFTP / SFTPになります。
Windowsであれば、私は WinSCP をおすすめしています。現状、実務で使うなら WinSCP と FileZilla の2択だと思っています。

WinSCPをすすめる理由は、
・操作が分かりやすい
・設定保存がしやすい
・再接続が簡単
・日本語対応
・SSH連携がしやすい
という点です。

SSHは初心者の方だと普段使わないと思いますが、FTP/SFTPフトで本当に重要なのは、アップロード途中で止まったときに、きちんと再開できるかです。
ここは結構大事です。

私の感覚だと、違いはこんな感じです。

・FileZilla
→ キュー再開が必要になることがある(半手動寄り)

・WinSCP
→ 再接続後に継続しやすい

なので、私は WinSCP を使います。
以前は FFFTP にかなりお世話になりましたが、途中で止まると基本やり直しになることが多く、かなり苦労しました。ここは本当に重要です。

WordPressのコアファイルは、wp-content を除いてもそれなりの数がありますし、環境によってはかなりのファイル数をアップロードすることになります。
この時点で転送が不安定だと、それだけで事故率が上がります。

ワードプレスコアのファイルを準備

復旧に使う、きれいなWordPressオリジナルファイルを用意します。ダウンロード元は公式です。

最新
https://ja.wordpress.org/download/

過去バージョン
https://ja.wordpress.org/download/releases/

※弊社は WordPress のマルウェアや乗っ取り復旧サービスなので、迅速に対応するため、ある程度のバージョンは ZIP と解凍済みの両方を保持しています。
ローカル側では、解凍したコアのディレクトリを作業しやすいようにリネームしておきます。

ローカル側
・wp-admin_
・wp-includes_

サーバー側
・Delete_Backupフォルダを作成

このあと、サーバー側の既存ディレクトリを退避しながら、クリーンなコアへ入れ替えていきます。

コアファイルのアップロード

コアディレクトリをリネームで入れ替える

WordPressコアのディレクトリは、瞬時にリネームして入れ替えます。
ここは、アップロードしながらぐだぐだ置き換えるより、このやり方のほうが事故が少ないです。

新しいファイルをリネーム
・wp-admin_ → wp-admin
・wp-includes_ → wp-includes

古いファイルをリネーム
・wp-admin → wp-admin_backup
・wp-includes → wp-includes_backup

この形で、まずコアディレクトリをクリーンなものへ切り替えます。

残りのコアファイルを入れ替える

次に、ルート直下のコアファイルを入れ替えます。
基本的には、下記のファイル以外は一旦 Delete_Backup フォルダへ退避します。

残すファイル
・.htaccess
・.user.ini
・wp-config.php

※ robots.txt や ads.txt がある場合もあります。ここは内容を見て判断してください。

退避するファイル
・index.php
・wp-config-sample.php
・wp-settings.php
・wp-load.php
・wp-login.php
・wp-mail.php
・wp-blog-header.php
・wp-cron.php
・xmlrpc.php
・license.txt
・readme.html

基本はこのあたりです。ただし、実際にはマルウェアが独自ファイルを置いていることもあるため、残す3ファイル以外はすべて一旦退避するくらいで考えたほうが安全です。

そのあと、新しいコアファイルをローカルからアップロードし、通常のWordPressの構成に戻します。

本来であれば、退避したファイルはそのまま削除してもよい場面はあります。
ただ、過去にはそのマルウェアがないと逆にWordPress自体が落ちるような、かなり気持ちの悪い個体もありました。実害は出ませんでしたが、その段階で一旦サイトを止めて、復旧を進めたことがあります。結構昔の話ですが、何回か冷や汗をかきました。

もし、この構成ファイルへ入れ替えた段階で大きく崩れるようであれば、このあとに行うプラグインの更新や入替えを先に進める判断も入ってきます。ここは実務判断です。

ここで一旦、コアファイル自体はクリーンな状態になります。
ただし、これで終わりではありません。すぐ次に wp-content の復旧へ進みます。理由は単純で、wp-content 側から再びコアが汚染される可能性があるからです。なので、間を空けずにそのまま進めます。

wp-contentの復旧

まずはバックアップ

ここでもう一度バックアップを取ります。
サーバー会社のバックアップがある場合でも、保険としてプラグイン側でもバックアップを取っておくほうが安全です。

ここでは UpdraftPlus を使います。復元が比較的わかりやすく、実務でも扱いやすいです。弊社のWordPress保守でも使っています。
使い方そのものは、ここでは省略します。必要なら調べてください。

他のプラグインが駄目という話ではありません。
ただ、復旧の現場では復元のしやすさがかなり重要です。
All-in-One WP Migration は拡張機能が必要になる場面がありますし、BackWPup は環境やサーバースペックの影響を受けやすい印象があります。
ここは好みもありますが、私は UpdraftPlus を使います。

入れ替えるプラグインの入手確認

プラグイン本体は、きれいなものと入れ替えれば、そのディレクトリ配下の不正ファイルを除去できるケースが多いです。
問題は、何をどうやって入れ替えるかです。

復旧でのプラグイン入替えでは、次を先に確認します。

  • 管理画面の「プラグインを追加」から、今でもインストールできるか
  • 以前は公式ディレクトリから入れられたが、今は配布終了していないか
  • 有料プラグインの場合、配布元からZIPを入手できるか
  • ライセンスが切れていないか

有料プラグインは、ここが結構見落とされます。
「復旧しようと思ったら、そもそも正規ZIPが手に入らない」というのは普通にあります。

公式サイトからのダウンロードが安心

独自配布のプラグインは、十分に信頼できる配布元でない限り、私はあまりおすすめしません。
多くの場合、代替プラグインがあります。まずはそちらを探します。

過去には、ライセンス面で微妙な配布物や、プラグイン有効化時に、配布者と思われる外部へ同意なしで通信するようなものも見てきました。
社内利用などで自社配布するケースは別ですが、通常は WordPress公式ディレクトリ経由で配布されるのが一般的です。

プラグインリストを把握する

プラグイン一覧画面から作ってもよいのですが、復旧ではサイトヘルスの情報タブから拾うと早いです。

管理画面 > ツール > サイトヘルス > 情報タブ

ここで次を把握します。

・MUプラグイン
・停止中のプラグイン
・使用中のプラグイン

この一覧が、あとで入れ替えるときの基準になります。
復旧中は「何が入っていたか」がすぐ分からなくなるので、先に控えておいたほうがいいです。

アクセス権 444 / 555 の確認

ここは、wp-content の復旧に入る前に一度見ます。
444 や 555 のファイル・ディレクトリが混じっていると、削除や入替えを邪魔されることがあるからです。

特に、フォルダが 555 になっている場合、その配下のファイルやディレクトリを通常の操作で消せないことがあります。
実務では、マルウェアが自分を消されにくくするために、こうした権限へ変えているパターンをよく見ます。
かなり強く疑うべき状態です。

このあと出てくる upgrade-temp-backup や plugins、languages が消せない、リネームできない、書き戻せないという場合は、まずここを見ます。
削除できない理由が、単純な操作ミスではなく権限で止められていることがあります。

「upgrade/upgrade-temp-backup」フォルダを削除

これらのフォルダは、WordPress更新時に一時的に作成されるディレクトリです。
処理が終われば不要なので、削除して問題ありません。必要になれば、更新時にまた自動生成されます。

ただし、削除できない場合は要注意です。
この場合は、前項で書いた 444 / 555 の権限 や所有者を確認します。
マルウェアが自分を消されにくくするために、ここを固めているケースがあります。

ここで一旦アクセスを解放します。

このあとは、作業を進めるために一時的にホームページへのアクセス制限を解除します。
制限をかけたままでは、管理画面やプラグインの操作が正常に行えないためです。

アクセス制限の解除方法(.htaccess)

一時的に設定した503のアクセス制限は、.htaccessの該当部分を無効化することで解除できます。
以下のように、行頭に「#」を付けて無効化します。

#ErrorDocument 503 /maintenance.html
#RewriteEngine On
#RewriteCond %{REMOTE_ADDR} !^xxx\.xxx\.xxx\.xxx$
#RewriteCond %{REQUEST_URI} !^/maintenance\.html$
#RewriteRule ^ - [R=503,L]

languagesディレクトリの中身をクリア

/wp-content/languages/ 配下には、WordPress本体・プラグイン・テーマの翻訳ファイルが入ります。
本来は翻訳用途のファイルしかない場所です。

構成は、基本的に次です。

・/wp-content/languages/
・/wp-content/languages/plugins/
・/wp-content/languages/themes/

通常、ここにあるのは次の3種類です。

・.po
・.mo
・.l10n.php

これらは WordPress が自動取得・再生成するため、問題があれば一度クリアして再構築できます。
実務では、このディレクトリにマルウェアが紛れ込んでいるケースがあります。
特に PHPファイルがある場合は要注意です。本来そこに置かれる想定ではありません。

やり方は次です。

・【FTP】wp-content/languages を languages_myao などにリネームする
 ※個人的には _backup、_old、_back のような名前は避けます。ありきたりすぎて、あとで見分けが付きにくいからです。

・【管理画面】サイト言語をいったん英語にしてから日本語へ戻す
 Settings > General > Site Language
 英語 → 日本語

これで /languages/ が再生成され、必要な翻訳ファイルが入り直します。

・【管理画面】外観 > テーマ > テーマを追加
 任意のテーマを入れると /languages/themes/ が再生成されます。

・【管理画面】プラグインをインストール
 必要に応じて /languages/plugins/ も再生成されます。

ここでデバッグポイント

ここで一度、もう1回バックアップを取ります。
無料版の UpdraftPlus は、少なくともこの段階ではコア一式を保存する用途ではなく、きれいにした languages や plugins 側を退避する保険として考えています。
ここまで整えたものを一度持っておけるのは大きいです。

復旧に失敗して、またぐちゃぐちゃにされると、結構泣けます。

プラグインを入れ替える

ここで、最初に絶対にやってはいけないことがあります。

「管理画面でプラグインを無効化して、そのまま削除して、再インストールする」
これは、やり方としてかなり危ないです。

理由は、プラグインによっては、データベース側の設定や保持データまで消えることがあるからです。
復旧どころか、そこからやり直しになることがあります。
なので、別の方法を取ります。というか、ここは本当にやり直しになるときがあります。

やり方は次です。

pluginsをリネイムして新規作成

・【FTP】wp-content/plugins を plugins_myao などへリネームする
 ※ここも _backup、_old、_back のような名前は個人的には避けます。

・【FTP】新しく plugins ディレクトリを作成する

この段階で、「インストール済みプラグイン」の画面へ行くと、
「プラグイン ●●● はエラーにより停止しました: プラグインファイルが存在しません。」
のような表示になり、結果的にすべて停止します。
後でリストを見ながら入れ直して有効化すれば問題ありません。

管理画面から順番に入れ直します。

  1. ・【管理画面】プラグイン > プラグインを追加
  2. ・必要なキーワードで検索
  3. ・各プラグインをインストール
  4. ・「インストール済みプラグイン」で一覧を確認
  5. ・表示や動作を確認する

ここは地味ですが、かなり大事です。
「何を戻したか」「何が戻っていないか」 を見失うと、復旧が一気に雑になります。この時点でプラグインは揃いました。

データベース(DB)とUploadsフォルダの検査

phpMyAdminのリスクを考える。

コアファイルの置換により、ファイル側はある程度きれいになりました。
次に見ていくのが、uploads フォルダとデータベース(MySQL、以下DB)です。ここは、汚染が残っている可能性があります。というより、実務では高確率で残っている前提で見ます。

DB操作は非常にリスクが高い作業です。
一歩間違えると、サイトが完全に壊れる可能性があります。

DBはFTPソフトで直接操作することはできず、一般的にはphpMyAdminなどのツールを使ってSQLを発行します。
しかし、操作ミスによって投稿データや設定が破損するケースもあるため、慎重な判断が必要です。
そのため、この記事ではphpMyAdmin で直接クエリを打って復旧する方法は推奨しません。
ここでは、まずプラグインを使って安全寄りに、かつ網羅的にDB内をスキャンする考え方を取ります。

phpMyAdmin を見ながら AI のチャットで復旧しようとするのは、正直かなり危ないです。
もしデータを修復不能にしたら、目も当てられません。

なお、弊社の実務では、phpMyAdmin による精密なクエリ発行と、プラグインによる広範囲スキャンを併用する、いわゆるハイブリッド体制で対応しています。
ただ、これは慣れているからできるだけであって、DBを触るときは今でも普通に緊張します。
プロでも緊張します。人間なので。
だから、使い慣れていない方が、本番の復旧で phpMyAdmin を触るのはおすすめしません。復旧ブログや AI を見ながら、その場で SQL を打つのはやめたほうがいいです。

phpMyAdmin では、たった1文字の打ち間違いで、数万件の投稿データや関連情報が一瞬で意味不明な文字列になったり、消えたりします。
バックアップがあるとはいえ、デジタル資産が飛ぶ可能性があるということです。

Uploadsフォルダも見る

ファイルの復旧がある程度進んでも、/wp-content/uploads/ 配下に不正ファイルが残っていることは普通にあります。
本来ここは、画像、PDF、添付ファイルなどを置く場所です。
なので、PHPファイル、見慣れない .htaccess、意味の分からないサブディレクトリ、ランダムな文字列のファイル名などがある場合はかなり注意です。

特に、画像やPDFに見せかけて、実際には不正コードの起点になっているケースもあります。
ここは「アップロード置き場だから安全」ではありません。普通に見ます。

この記事の方針

この記事は、バックアップが使える前提で、ファイル入替えと安全寄りの復旧を進める記事です。なので、DBに対していきなり手でクエリを打つようなやり方は主線にしません。

DBの直接調査や SQL ベースの精査は、難易度が一段上です。そこは別記事レベルの話になります。
本記事では、まず 「ファイルをきれいにする」「uploads を確認する」「プラグインでDB側の異常を洗う」 という順番で進めます。

Wordfence Securityの導入

DB は phpMyAdmin を直接使わない前提で、プラグインの Wordfence Security を導入して対応します。
イメージとしては、WordPress 用のウイルス対策ソフトのようなものです。WAF、マルウェア検知、ログ確認をひとつの画面で見やすく扱えるため、復旧時の確認にも使いやすいです。
GMOインターネットグループのレンタルサーバー・ロリポップでも、WordPress のセキュリティ対策のひとつとして Wordfence が紹介されています。
参考URL: https://lolipop.jp/media/wordpress-guide/
参考URL: https://www.wordfence.com/products/wordfence-free/

WordPress 管理画面から追加する

【管理画面】→【プラグイン】→【プラグインを追加】→ 検索欄で wordfence と入力します。
一番最初に出てくることが多い Wordfence Security – Firewall, Malware Scan, and Login Security をインストールして有効化します。

無料で使えるが、ライセンス登録は必要 Wordfence は無料版でも使えます。
初回セットアップ時にライセンス登録を求められるので、画面の案内に沿って進めます。

無料ライセンスの取得方法 Wordfence のサイトへ移動し、Get Free Licence をクリックします。
その後、I’m OK waiting 30 days for protection from new threats を選び、メールアドレスを入力して必要項目にチェックを入れ、Register をクリックします。
入力したメールアドレスにライセンスキーが届くので、Wordfence の画面へ戻り、既存のライセンスをインストール から登録します。
参考URL: https://www.wordfence.com/wordfence-free-vs-premium/

無料版の注意点 無料版でもマルウェアスキャンそのものは使えます。
ただし、新しいマルウェアシグネチャ と 新しい WAF ルール の反映は Premium より約30日遅れます。
一方で、全部の基本スキャン機能が30日遅れるわけではありません。
公式比較では、無料版でもマルウェアスキャナや脆弱性スキャナは利用でき、Premium ではリアルタイム反映や追加機能が使えるという整理になっています。
また、無料版では次の3つのチェック機能はロックされており、Premium 限定です。
・ブラックリストチェック
・スパム関連チェック
・IP がスパム送信源かどうかのチェック
つまり、無料版は一部機能が使えず、新しい脅威への対応が30日遅れるという理解が正確です。
参考URL: https://www.wordfence.com/free-wordpress-malware-scanner/
参考URL: https://www.wordfence.com/wordfence-free-vs-premium/

無料版でも使える基本スキャン 無料版でも、次のような基本的な確認は行えます。

  • サーバーの状態
  • ファイルの変更
  • マルウェアスキャン
  • コンテンツの安全性
  • 公開ファイル
  • パスワード強度
  • 脆弱性スキャン
  • ユーザーとオプションの監査

これらをひっくるめて 全部30日遅延 と書いてしまうと正確ではありません。
遅延の中心は、新しいシグネチャや新しいルールに依存する部分です。
参考URL: https://www.wordfence.com/free-wordpress-malware-scanner/
参考URL: https://www.wordfence.com/wordfence-free-vs-premium/

Wordfenceによるマルウェア対策のワードプレスレスキューの推奨設定

ここでは、Wordfence を常時運用の完成形として入れるというより、復旧後の残留確認と再感染の手がかりを拾うために使います。見た目が戻っていても、中身まで戻っているとは限りません。そこを確認します。

まず開く場所
Wordfence → すべてのオプション を開きます。

自動更新は有効にする 新しいバージョンがリリースされたら、Wordfence を自動的に更新しますか?
ここはチェックを入れておきます。復旧中は、セキュリティプラグイン側の更新漏れを減らしたほうが安全です。
参考URL: https://www.wordfence.com/help/dashboard/options/

Wordfence が IP を取得する方法
Wordfence が IP を取得する方法 は、環境に合わせて確認します。
特に Cloudflare を使っている場合 は、IP の取り方を誤るとアクセス元の判定がずれることがあります。
Cloudflare 利用時は、Wordfence 側の IP 取得設定を確認してください。
参考URL: https://www.wordfence.com/help/dashboard/options/

一般的なオプションでチェックをいれたい項目
WordPress のバージョンを隠す
アップロードディレクトリのコード実行を無効化
ここで一回 変更を保存 を押します。

uploads 直下の .htaccess が邪魔をして保存できないことがあります。この設定は、実務では保存時にエラーになることがあります。
アップロードディレクトリのコード実行を無効化する がうまく通らないときは、/uploads/ 直下に正しくない .htaccess が残っていることがあります。
不自然な内容であれば、まず退避したうえで削除し、必要な設定を再生成します。
その後にもう一度 変更を保存 を押すと実務上は通ります。

ブルートフォース保護
空白の User-Agent と Referer を使用して POST 要求を送信する IP をブロックする は有効化を検討します。こういう雑なアクセスは、復旧中でも飛んでくることがあります。

基本設定で見ておきたい項目 復旧確認としては、次のような箇所チェックをいれることが、マルウェアをあぶり出す鍵です。

  • テーマファイルをリポジトリのバージョンと照合して差分を確認する
  • プラグインファイルをリポジトリのバージョンと照合して差分を確認する
  • WordPress インストール外のファイルをスキャンする
  • 画像やバイナリに見えるファイルの中に、実行可能コードが混ざっていないか確認する

こうした見方は、Wordfence のハッククリーンアップの考え方とも噛み合っています。
参考URL: https://www.wordfence.com/docs/how-to-clean-a-hacked-wordpress-site-using-wordfence/
参考URL: https://www.wordfence.com/free-wordpress-malware-scanner/

サブディレクトリに WordPress を入れている場合 サブディレクトリなどに WordPress を入れている場合は、スキャン範囲の設定に注意してください。
ルート直下ではない構成なのに広く見すぎると、確認対象がずれることがあります。
ここはサイト構成に合わせて調整します。

変更を保存する 一通り設定したら 「変更を保存 」を押します。

スキャンをかける

Wordfence → スキャン → 新しいスキャンを開始する をクリック
バーが動き出したら、上の小さい文字で出ます。
アクティビティログをメールする / フルログを見る / ログを表示
のうち、ログを表示 を押すと動きが見えます。
ここがきちんと進み出せば、スキャン自体は問題なく走っています。
参考URL: https://www.wordfence.com/docs/how-to-clean-a-hacked-wordpress-site-using-wordfence/

結果をみる

発見した結果には、たとえば次のようなものが出ます。

  • ・問題は見つかりません
  • ・投稿におかしなスクリプトが埋め込まれている
  • ・マルウェアと思われるファイルがある
  • ・アップデートが必要で、かつ脆弱性が存在している
  • ・アップデートはないが、脆弱性が存在している

「マルウェアと思われるファイルがある」は通常は削除となりますが、ここで重要なのは、出てきたものを全部すぐ消すことではありません。
正規ファイルなのか、不正ファイルなのかを見極めながら、問題を1つずつ潰していきます。
ただし、Wordfence の結果は万能ではなく、実務では「全部を精査する」のが現実的でないケースもあります。
参考URL: https://www.wordfence.com/docs/how-to-clean-a-hacked-wordpress-site-using-wordfence/

この段階での Wordfence の位置づけ

Wordfence は、これひとつ入れたら全部終わる魔法の道具ではありません。
ただ、復旧後の取りこぼし確認と、残留マルウェアの見える化にはかなり役立ちます。
DB を phpMyAdmin で直接いじらない前提なら、なおさら一度しっかり見ておく価値があります。

でも 6,400のファイルは全部見れない

結果の数は、実務では全部を精査しきれないことがあります。
Wordfence の結果で .htaccess が大量に出ることは珍しくなく、実務では 6400 件近く出るようなケースもあります。
これを 1つずつ中身まで確認するのは、時間、費用、ユーザー負担を考えると現実的ではありません。
そのため復旧では、.htaccess を細かく追いかけ切るより、一度整理して削除し、必要なものを再作成する 方針を取ることがあります。
特にプラグイン側で自動生成・再生成される .htaccess は、いったん消して整理したほうが早いことがあります。その後、プラグインの有効化・無効化 を行うことで、必要な設定が再作成されるケースは少なくありません。

uploads以外ではマルウェアは出てきてほしくない

uploadsディレクトリ以外はクリーンアップ済みのため、本来はマルウェアが検出されない状態であることが前提です。もしuploads以外からマルウェアが検出された場合は、クリーンアップが不完全である可能性が高く、再度見直しが必要です。

復旧では理想論よりコストと事故防止を優先する

これは、理想と実務、そして私の考えです。
本来は全部確認したいところですが、復旧では時間、費用、ユーザー負担の限界があります。
そのため、確認不能なものを延々と追い続けるより、最悪の事態を避けながら安全側に寄せることを優先します。
ここは実務上の限界値でもあります。

なぜ .htaccess が大量に生成されるのか

マルウェアは、各ディレクトリごとに .htaccess を自動生成し、その配下にある PHP などの実行挙動を制御しようとすることがあります。
その結果、正規の復旧処理や削除作業をやりにくくしながら、不正な動作だけを残そうとする個体があります。このため、.htaccess が大量にばらまかれている場合は、1件ずつ読むより、全体を整理して安全側で戻す という判断が実務では必要になります。

途中でもバックアップを取る

この判断を安全に進めるため、作業前だけでなく、途中段階でもバックアップを取ります。
これは、再作成に失敗した場合や、想定外の不具合が出た場合にすぐ戻せるようにするためです。
復旧では、「進めること」と同じくらい、「いつでも戻せること」が重要です。

まとめ・復旧は「作業」ではなく「判断」です。

WordPressの乗っ取り復旧は、見た目が正常でも内部に不正コードが残ることがあるため、「治ったように見える状態」を前提に進める必要があります。

基本は、遮断・入替え・確認の3つです。
特に、上書きではなく入替えが重要です。

実務では、.htaccessが大量生成されたり、管理者だけ正常に見えるマルウェアも確認されています。
そのため、すべてを精査するのではなく、構造ごと整理する判断が必要になります。

難しい場合は無理をせず、専門業者への依頼も検討してください。

執筆責任・前田美知太郎(CreativeStudio樂・ワードプレスレスキュー代表)

著者プロフィール
WordPressは2007年から実務で扱い始め、当時はMovable Typeが主流の中で運用・構築の経験を積む。 インターネットプロバイダーのインフラエンジニア出身。サーバー・ネットワーク・セキュリティの基礎を現場で習得し、警察へのログ提出やログ整合性の確認など証跡管理の実務経験を有する。
WordPress構築・サーバー設計・マルウェア復旧・セキュリティ対策を中心に実務に従事。現在はAWS・各種VPS環境でのインフラ構築、CloudflareによるCDN・WAF運用、ログ解析や攻撃分析を含む実践的なセキュリティ対応を行っている。
WordPressの障害復旧は1,400件以上の対応実績。 守秘義務契約(NDA)により詳細は公開不可だが、公的機関・教育機関・金融系・観光関連・放送関連のサーバーおよびセキュリティ設計・構築に従事。
個人から上場企業、大学・教育機関、IOC参加団体、制作会社など幅広い領域の改ざん・マルウェア感染復旧に対応。初動対応から復旧までを担当。
近年は悪意あるBOTの挙動データの収集・分析を行い、検知・対策への活用にも取り組む。 独立行政法人情報処理推進機構(IPA)セキュリティプレゼンター、デジタル庁デジタル推進委員としても活動。