「セキュリティプラグインでスキャンしたのに、
WordPressの感染が見つからない」と困っていませんか?
今回の復旧事例では、マルウェア本体がPHPファイルではなく、
WordPressのデータベースに隠されていました。
公開画面や管理画面が普通に見えても、ファイルとデータベースを結び付けて調べなければ、
バックドアやSEOスパム用の仕組みを見落とすことがあります。
WordPressの復旧を多数手がけてきたよこやま良平です。わたしの現場経験をもとに、データベース内へ隠されたバックドアの見つけ方と、安全な復旧順序を解説します。
- ファイルスキャンで見つかりにくいDBバックドアの仕組み
- テーマの数行とwp_optionsを結び付けた調査方法
- 偽のバックアップテーブルと隠し管理者の実例
- 証拠を残しながら安全に駆除する順番
- 同じ感染を繰り返さないための再発防止策
結論から言うと、WordPressの感染調査はファイルだけでは不十分です。
テーマやプラグインが読み込むデータベース値、別プレフィックスのテーブル、管理者情報まで確認する必要があります。
この記事では、ご依頼者様のサイト名、ドメイン、認証情報などを伏せ、
復旧判断に必要な技術情報だけを掲載しています。
WordPressデータベースのバックドアが見つかった復旧事例
今回確認したのは、業務で使われているWordPressサイトです。
既存のセキュリティスキャンでは、データベース内のバックドア本体が明示的に検出されていませんでした。
ただし、これは「セキュリティプラグインが役に立たない」という意味ではありません。
スキャン対象や検出方式によって、確認できる範囲が違うということです。
- 公開画面は大きく崩れていない
- 目立つWebシェルはテーマ内で確認できない
- テーマのfunctions.php冒頭に不自然なコードの痕跡がある
- データベース全体はまだ詳しく調べられていない
無料・有料を問わず、外部URLスキャン、ファイルスキャン、データベース検査にはそれぞれ役割があります。
検出されなかったことだけで、安全とは判断できません。

WordPressテーマの数行からデータベースの本体を発見
感染の手がかりは、テーマのfunctions.php冒頭に残っていた短いコードでした。
見つかった時点ではコメントアウトされ、実行されない状態になっていました。
// $themes_css = get_option( 'themes_css' );
// if ( $themes_css ) {
// $themes_css['themes'] = $themes_css['themes']();
// require_once $themes_css['footer'];
// }themes_cssという名前だけを見ると、テーマの見た目を保存する設定にも見えます。
しかし、データベースから取り出した値を関数として呼び出し、さらにファイルを読み込む構造は正規のCSS設定とは異なります。
wp_optionsのthemes_cssに約9KBの値
データベースのwp_optionsを確認すると、themes_cssという設定が残っていました。
値の中には、16進数で表現された長いPHPコードが格納されていました。

16進数の部分を実行せずに静的解析すると、PHPコードへ戻ることを確認しました。
そこには、外部から送られた命令を実行できる処理や、外部サーバーとの通信処理が含まれていました。
- 秘密のPOSTパラメータを受け取り、任意のPHPコードを実行する
- 外部サーバーから内容を取得する
- 訪問者のIPアドレスやログイン状態で表示を変える
- WordPressのテーブル接頭辞を偽テーブル側へ切り替える
- 通常の管理画面に出ないスパム記事を返す
WordPressデータベースに偽のテーブルと隠し管理者
この感染は、themes_cssだけを削除すれば終わるものではありません。
データベースには、backupdb_wp_で始まる偽のWordPressテーブルが23個作られていました。
名前だけを見るとバックアップに見えますが、実際には別の投稿、ユーザー、設定を保存できる一式です。
正規サイトとは無関係な英語SEO記事や、IP判定用と考えられる323件のデータも確認しました。
通常のユーザー一覧には見えない管理者
まず、WordPress管理画面のユーザー一覧で、表示されている管理者を確認しました。
掲載画像では、依頼者に関係するユーザー名、氏名、メールなどをすべてマスキングしています。

管理画面に表示される一覧だけでは、感染用の別テーブル側まで確認できません。
偽テーブルのbackupdb_wp_usersには、通常テーブルに存在しないID 123456のユーザーがありました。
対応する権限情報には管理者権限が設定され、メールアドレスや表示名は空欄でした。
この不整合も、正規運用のユーザーではないと判断する重要な根拠です。

このユーザーは通常の管理画面を眺めるだけでは、感染の全体像として把握できません。
攻撃者が接続先テーブルを切り替えた時だけ利用する、別のWordPress環境として残されていたと判断しました。

WordPressのセキュリティスキャンで見つかりにくかった理由
今回のバックドアが見つかりにくかった最大の理由は、危険な処理が複数の場所へ分割されていたことです。
ファイル側だけ、データベース側だけを見ても、動作全体を理解しにくい構造でした。
- テーマ側はデータベースから値を読む短いローダーだけだった
- 本体はwp_options内で16進数に変換されていた
- スパム投稿と管理者は別プレフィックスのテーブルに隠されていた
Wordfenceでバックドアが検出されなかった理由
当該サイトではWordfenceのスキャンを実行し、ファイルの変更、マルウェアスキャン、
コンテンツの安全性など、複数の検査が完了した状態を確認しました。
それでも、wp_optionsのthemes_cssに保存されたバックドア本体や、backupdb_wp_で始まる偽テーブル群は、検出結果へ明示されていませんでした。

Wordfenceはファイルだけでなく、投稿、コメント、一部のWordPressオプションも検査します。
しかし、データベース内のすべてのテーブルと値を、実行コードとして完全解析するわけではありません。
Wordfence公式も、感染の一部がスキャン対象外のデータベーステーブルにあり、
手動でのデータベース駆除が必要になる場合があると案内しています。
セキュリティスキャンは重要な一次確認です。ただし、結果に何も出ないことは、データベース、別テーブル、管理者、Cronまで安全である証明にはなりません。
今回の感染は、テーマ側の短いローダーとDB内のペイロードを関連付け、
16進数の値を実行せずに解析して初めて、バックドアと判断できました。
Wordfenceで異常が出ないのに不審な症状が続く場合や、DB内の値を判断できない場合は、
削除を始める前にWordPress復旧の専門家へ調査を依頼してください。
テーマ側のコードには、よく知られたevalやbase64_decodeが直接書かれていません。
関数名や引数もデータベースから取り出すため、単純な文字列検索では弱い判定になりやすいのです。
また、管理者やログイン中の接続元には不正表示を見せない条件もありました。
サイト所有者が自分のパソコンで確認しても正常に見えるため、検索結果や非ログイン状態との違いを確認する必要があります。

themes_css型バックドアはGootloader系の調査報告と一致
今回確認したthemes_css、テーマ側ローダー、backupdb_テーブル、IPによる表示制御は、
過去に公開されたセキュリティ調査の特徴と一致します。
Sucuriは2018年、WordPressテーマからthemes_cssを読み込み、偽のバックアップテーブルへ接続してSEOスパムを配信する仕組みを報告しました。
後年のSophosによるGootloader調査でも、同じbackupdb_wp_lstatや、POST経由の簡易コマンドシェルが解析されています。


ただし、公開された攻撃事例と特徴が一致しても、今回の初期侵入経路までは断定できません。
古いプラグイン、漏えいした認証情報、別のWebシェルなど、侵入口の判断にはアクセスログや更新履歴が必要です。
WordPressデータベースのバックドアを駆除した手順
復旧では、怪しいものを先に消すのではなく、原本保全、範囲確認、隔離・削除、再確認の順番を守ります。
データベース操作を誤ると、正常な設定や投稿まで失うためです。
DELETEやDROPは元に戻せない場合があります。ファイル、データベース、アクセスログを別の安全な場所へ保存し、復元できることを確認してから作業してください。
1. ファイル・DB・ログを原本保全
最初にWordPress全体とデータベースを保存し、取得日時とSHA-256を記録しました。
削除前の状態を残しておけば、後から侵入経路や取り残しを調べ直せます。
2. themes_cssと偽テーブルを隔離・削除
wp_optionsのthemes_cssを削除し、backupdb_wp_で始まる23テーブルを対象確認後に削除しました。
似た名前の正規バックアップがないことを、テーブル構造と内容で確認してから実施しています。
3. テーマ側ローダーを行ごと削除
functions.phpのコードは、コメントアウトのまま残さず削除しました。
再侵入時にコメント記号だけを外して再利用される可能性を減らすためです。
4. Webルート全体と別の永続化を確認
テーマだけで終わらせず、プラグイン、mu-plugins、uploads、WordPressルート、.htaccess、.user.ini、Cron、管理者ユーザーも確認しました。
バックドア本体を削除しても、再生成元が残っていれば復旧にはなりません。

WordPress復旧中に正規の.user.iniを消した失敗
今回の作業では、駆除途中にPHPの警告が画面へ表示される事態も起きました。
原因はマルウェアではなく、正規の.user.iniを削除されたことです。
Warning: Undefined array key 9 in .../header-parts-navi.php on line 38テーマにはPHP 8で警告が出る古い処理がありましたが、以前は画面表示を抑える設定が有効でした。.user.iniを消したことで、もともと存在した警告が見えるようになったのです。
正規の.user.iniを復元し、テーマ側も表示内容を変えずにPHP 8へ対応させました。
この事例からも、名前や設置場所だけでファイルを削除してはいけないことが分かります。
- .user.iniや.htaccessなどのサーバー設定ファイル
- uploads内のindex.phpなど、空ディレクトリ保護用ファイル
- キャッシュやセキュリティプラグインが作る正規ファイル
- 提供元と役割をまだ確認できていないカスタムコード
WordPressデータベース感染の再発防止で行うこと
駆除後は、データベースだけをきれいにして終わらせず、侵入に使われた可能性がある権限と公開資産を見直します。
バックドアがあった以上、認証情報は漏えいしている前提で交換する方が安全です。
- WordPress管理者、サーバー、FTP・SSH、DBの認証情報を交換する
- WordPressの認証用キーとソルトを更新して既存セッションを失効する
- 本体、テーマ、プラグインを正常な配布元と照合して更新する
- 削除済み・放棄・不要なプラグインとテーマを撤去する
- 管理者、Application Password、Cron、外部通信を再点検する
- 非ログイン状態、検索経由、複数端末で不正表示の再発を確認する
また、通常のwp_以外で始まるテーブル、autoloadされる大容量オプション、見覚えのない管理者を定期的に確認すると、同系統の感染を早く見つけやすくなります。

WordPressデータベースのバックドアでよくある質問
WordPressデータベースのバックドア復旧事例まとめ
今回のWordPress感染では、テーマ内の短いローダーと、データベースのthemes_cssが組み合わさっていました。
さらに偽のbackupdb_wp_テーブルへ、スパム記事、IP情報、隠し管理者が保存されていました。
- マルウェア本体はデータベースに隠れることがある
- ファイルとDBを関連付けないと動作全体を見落とす
- 通常の管理画面に出ない投稿や管理者が存在する場合がある
- 削除前の証拠保全と、削除後の再検査が必要
- 駆除と認証情報交換、更新、監視までが復旧作業
「スキャンでは何も出ないが、検索結果やアクセスの様子がおかしい」という場合は、
不審ファイルだけでなく、データベース、別テーブル、管理者、Cronまで調べてください。
WordPressデータベースの感染を自分で判断できない時は

Wordfenceで異常が出なかったからといって、安全だとは断定できません。
今回のように、バックドア本体がデータベースに隠れ、偽テーブルまで作られている場合があります。
DB内の長い文字列が安全か分からない、バックドアや偽テーブルをどこまで消すべきか判断できない場合は、
誤削除する前に、WordPress復旧の専門家であるクイックレスキューへご相談ください。
- Wordfenceでスキャンしても原因が見つからない
- wp_optionsに見覚えのない長い値がある
- 通常と異なる接頭辞のテーブルが増えている
- 管理画面に出ない投稿やユーザーが疑われる
- 自分で削除してサイトを壊すのが心配
- 駆除から再発防止までまとめて依頼したい
- 万一復旧できない場合やマルウェア駆除できない場合は全額返金保証で安心
- 90日間再感染保証・動作保証で安心
- 初期費用・調査費用0円で安心
