はじめに

先だっての記事では、

WordPressは世界でもっとも狙われるCMS

という話をしました。そこで今回は、実際に私のサーバへ飛んできたログを見ながら、攻撃者はどんな順番でサイトを調べるのかを追ってみます。

もちろんIPやホスト名はダミー化しています。

今回のログ

まず最初に来たアクセスはこちらです。

[ security2:error] [client 192.0.2.1] ModSecurity: Warning. Found 129 byte(s) in REQUEST_BODY outside range: 38,44-46,48-58,61,65-90,95,97-122. [file "REQUEST-920-PROTOCOL-ENFORCEMENT.conf"] [id "920273"] [msg "Invalid character in request (outside of very strict set)"] [data "REQUEST_BODY=format=1&key_name=0.central.updraftplus.com&udrpc_message=004AA==000000..."] [hostname "example.com"] [uri "/wp-admin/admin-ajax.php"]

[ security2:error] [client 192.0.2.1] ModSecurity: Warning. Pattern match "(?i)[!=]=|&&|..." at ARGS:udrpc_message. [file "REQUEST-942-APPLICATION-ATTACK-SQLI.conf"] [id "942120"] [msg "SQL Injection Attack: SQL Operator Detected"] [data "Matched Data: == found within ARGS:udrpc_message: 004AA==000000..."] [hostname "example.com"] [uri "/wp-admin/admin-ajax.php"]

[ security2:error] [client 192.0.2.1] ModSecurity: Warning. Pattern match ... at ARGS:udrpc_message. [file "REQUEST-942-APPLICATION-ATTACK-SQLI.conf"] [id "942432"] [msg "Restricted SQL Character Anomaly Detection (args): # of special characters exceeded (2)"] [data "Matched Data: == found within ARGS:udrpc_message: 004AA==000000..."] [hostname "example.com"] [uri "/wp-admin/admin-ajax.php"]

[ security2:error] [client 192.0.2.1] ModSecurity: Warning. Operator GE matched 0 at TX:blocking_inbound_anomaly_score. [file "REQUEST-949-BLOCKING-EVALUATION.conf"] [id "949110"] [msg "Inbound Anomaly Score Exceeded (Total Score: 0)"] [hostname "example.com"] [uri "/wp-admin/admin-ajax.php"]

[ security2:error] [client 192.0.2.1] ModSecurity: Warning. Operator GE matched 0 at TX:blocking_inbound_anomaly_score. [file "REQUEST-949-BLOCKING-EVALUATION.conf"] [id "949110"] [msg "Inbound Anomaly Score Exceeded (Total Score: 0)"] [hostname "example.com"] [uri "/wp-content/plugins/wp_uwxdmva/wp_uwxdmva.php"]

この意図を見てみましょう。

key_name=0.central.updraftplus.com
udrpc_message=...

となっています。ここでWordPressを触っている人ならピンとくるかと思います。攻撃者は

「このサイトはWordPressで、しかもUpdraftPlusが入っている」

という前提で通信しています。

ModSecurityの反応

1. リクエストの偽装と第一段階の狙い

最初のログで、リクエストボディの中に key_name=0.central.updraftplus.comudrpc_message=004AA==... という文字列が含まれています。

これは、UpdraftPlusが外部のリモート管理サーバー(UpdraftCentralなど)と通信する際のRPC(リモートプロシージャコール)メッセージの形式です。

攻撃者は、ターゲットのWebサイトでUpdraftPlusが動いている、もしくは過去に脆弱性(例:CVE-2022-0633など、認証をバイパスしてバックアップをダウンロードしたりスクリプトを実行できたりした脆弱性)が存在していたことを期待して、このリクエストを送信しています。

udrpc_message の中身は一見するとランダムな文字列やBase64エンコードされたデータのように見えますが、WAFはここに「==」などの特定の記号が含まれていること、および使用が制限されている文字コードが大量に含まれていることを検知しました。そのため、ルール番号920273(プロトコル違反・不正文字)や、ルール番号942120、942432(SQLインジェクションのシグネチャ誤検知、または記号の過剰検知)が作動しています。

ここでの攻撃者の意図は、偽装した遠隔操作メッセージをプラグインに処理させ、サーバー内部に不正なファイルを書き込ませること(ファイルアップロード、あるいはコード実行によるファイル生成)にあります。

第二段階:設置したバックドアへのアクセス

注目すべきは、時系列の後半に記録されているログです。最初のリクエスト(09:11:30)からわずか2秒後(09:11:32)以降、アクセス先が以下のURLに変化しています。

/wp-content/plugins/wp_uwxdmva/wp_uwxdmva.php

WordPressに「wp_uwxdmva」という正規の有名プラグインは存在しません。ランダムに生成されたような不自然な文字列のディレクトリとファイル名です。

この挙動から、攻撃の仕組みと意図がはっきりと浮かび上がります。

  • ・ステップA:
    • まず /wp-admin/admin-ajax.php に対する偽装リクエストにより、脆弱性を突くか、あるいは認証をすり抜けて、サーバー上のプラグインディレクトリ内に「wp_uwxdmva.php」という不正なPHPスクリプトを生成・設置させようとした。
  • ・ステップB:
    • その直後、設置が成功したかどうかを確認するため、あるいは設置したファイルに外部からコマンドを送り込んで実行(バックドアの起動)させるために、そのファイルへ直接アクセスを試みた。

同じURLに対して1秒未満の間隔で連続してアクセスが発生しているのは、自動化された攻撃ツール(ボット)が、ファイルの存在確認やコマンド実行のコマンドを機械的に連打しているためです。

攻撃者の頭の中

ここで時系列を改めて見てみましょう。

  1. admin-ajax.phpへ通信(POST)
  2. 成功したと思っている(侵入成功)
  3. バックドアが配置された前提(PHPシェル作成)
  4. そのPHPへアクセス(PHPシェル実行)

までを完全自動で行っています。

なのに攻撃者は失敗に気付いていない

繰り返しますが、私のVPSでは最初の

admin-ajax.php

自体が存在しません。当然バックドアも生成されません。しかしボットは生成されたはずという前提で

wp_uwxdmva.php

へアクセスします。

つまりボットは

成功したかどうか

を確認しているのではなく、決められたシナリオを最後まで実行しているだけです。

なぜWordPressがここまで狙われるのか

理由は単純です。世界中には数千万サイトものWordPressがあります。インターネットに存在する全サイト(CMSではなく!)42%がWordpressというデータもあるほどです。攻撃者から見ると

100万サイトのうち、42万サイトを手当たり次第に侵入を試み、1でも引っかかれば大成功という世界です。

一人一人を狙う必要はありません。成功率が0.01%でも十分利益になります。

ログから分かること

今回のログだけでも攻撃者は

  • WordPressを前提としている
  • UpdraftPlusまで想定している
  • 成功後のバックドア設置まで自動化している
  • 侵入後の確認まで自動化している

ということが分かります。今回は単純な

/wp-login.php

へのアクセスとは違い、

侵入から永続化(Persistence)までを一連の流れとして実装した自動ツールであることが読み取れます。

このログで特に価値があるのは、「一連の流れ」が1つのIP・数秒の間に記録されていることです。

  1. /wp-admin/admin-ajax.php に対して、UpdraftPlusを装ったPOSTリクエストを送る。
  2. 数秒待つ。
  3. /wp-content/plugins/wp_uwxdmva/wp_uwxdmva.php にアクセスする。

この3段階が連続しているため、「WordPressらしいURLを片っ端から試している」のではなく、「侵入→バックドア設置→バックドア起動」までを一つのシナリオとして実行するボットであることがかなり強く示唆されます。

ログは「攻撃の失敗」ではなく「攻撃者の設計図」

私は攻撃ログを見るたびに、

「また攻撃された」

とは考えません。どちらかというと

「攻撃者は今回はこういう設計思想でツールを作ったのか」

という視点で眺めています。今回のログも、

WordPressという巨大な市場を相手にした、完全自動化された侵入シナリオをそのまま見せてくれる教材でした。

サーバは無傷でした。しかし、ログには攻撃者の思考が残っていました。

余談

筆者はこの手の「騙しのテクニック」は好きです。「ミステリの謎解き」や「奇術の種明かし」或いは「使ったイカサマ」など。

ただし、それは「自分が被害に遭わないから楽しめる」のであって、このログ解析をエンターテインメントとして楽しめるのは

  • そもそも侵入されやすいCMS(Wordpress)は自前では運用していないこと
  • 日々サーバを管理して、WAFを導入し
  • Apacheを調整し
  • 防御手段を整えている
  • 暇があればログを観察する

に過ぎません。

ログには、サーバーへ送られたHTTPリクエストだけが記録されているわけではありません。その奥には、

  • 「どうすれば侵入できるか」を考えた誰かの発想
  • それを自動化したツールの設計思想

等が透けて見えます。

私にとってログ解析とは、防御のための作業であると同時に、そうした「思考の痕跡」を読むことでもあります。

なので、これが「笑い話として楽しめる」程度にはセキュリティの強度は高めていきたいという「やや斜め上からの」お話しでした。