テーマをCocoonに変更しました!
その他

PowerShellでアクセスログを調べたら1日3,000回の攻撃が!KUSANAGIでxmlrpc.phpを守る方法

FavoriteLoadingお気に入り登録
その他

はじめに:自分のサイト、どれくらい見られてるの?

ConoHa VPS(KUSANAGI)でWordPressサイトを動かしていると、ふと「今日は何人くらい来てくれたのかな?」と気になりますよね。

そこで、Windowsに最初から入っている「PowerShell(パワーシェル)」を使って、サーバーの中にある「アクセスの記録(ログ)」をのぞいてみました。

すると…1日およそ3,000回、知らない誰かがWordPressにログインしようとしていることが発覚!

この記事では、

  • PowerShellでアクセス数を調べる方法
  • GoAccess(ゴーアクセス)でグラフ付きのレポートを作る方法
  • 見つけた攻撃を、Jetpackアプリは使えるままブロックする方法

を、小学生でもわかるように、つまずいたポイントも全部ふくめて説明します。

この記事の作業環境

項目内容
サーバーConoHa VPS
OSAlmaLinux 9
KUSANAGIVersion 9.11
Webサーバーnginx 1.29
自分のパソコンWindows(PowerShell)
サイトWordPress 3サイト(Jetpack使用)

まずは言葉の説明

むずかしい言葉が出てくるので、先にたとえ話で説明しておきます。

言葉たとえると…
VPSインターネット上にある「自分専用の家」。サイトはこの家に住んでいます。
PowerShell文字で命令を打ちこむ黒い(青い)画面。Windowsに最初から入っています。
SSH自分のパソコンから、VPSという家に入るための「秘密のトンネル」。
ログ家の玄関にある「来客ノート」。誰がいつ来て、どの部屋に行ったかが全部書かれています。
nginx(エンジンエックス)玄関に立っている「門番」。お客さんを家に通すかどうか決めます。
xmlrpc.phpWordPressの「裏口」。スマホアプリなどが使う入口ですが、悪い人にもよく狙われます。
JetpackWordPressの便利プラグイン。スマホのJetpackアプリは、この裏口を通ってサイトとやりとりします。
200門番の返事で「どうぞ、お入りください」。
403門番の返事で「あなたは入れません!」。

手順1:PowerShellからVPSに入る

Windowsのスタートボタンを右クリックして「ターミナル」または「Windows PowerShell」を開きます。そして、次の命令を打ちます。

ssh -o ServerAliveInterval=60 -p 12345 root@203.0.113.1

「12345」は自分のSSHポート番号、「203.0.113.1」は自分のVPSのIPアドレスに書きかえてください。日本語の「ポート番号」などをそのまま貼り付けても動きません(私はやりました…)。

-o ServerAliveInterval=60 は「60秒ごとに、まだつながってるよ!と合図を送る」という意味です。これを付けないと、しばらく放っておいたときに勝手に接続が切れてしまうことがあります。

パスワードを入れて、画面にKUSANAGIの大きなロゴが出たら入れました。

今どこにいるか見分けるコツ

これがとても大事です。画面の一番下の行を見てください。

表示今いる場所
[root@vm-xxxx ~]#VPSの中(サーバー)
PS C:\Users\あなたの名前>自分のパソコン

命令によって「VPSで打つもの」と「パソコンで打つもの」があるので、ここを間違えると動きません。

手順2:来客ノート(ログ)の場所を探す

KUSANAGIでは、サイトごと(プロファイルごと)にログが分かれています。まずはプロファイルの一覧を見ます。

ls /home/kusanagi/

私の場合は kinrimypcnandemowebcss の4つが出てきました。今回はmypcを例に進めます。

cd /home/kusanagi/mypc/log/nginx/
ls

ファイルがたくさん出てきます。

ファイル名中身
access.loghttp(鍵なし)のアクセス。ほとんどhttpsへの転送だけなので、あまり役に立ちません。
ssl_access.log-日付https(鍵あり)のアクセス。本命はこっち!
〜.gz過去の日のログを圧縮(ぎゅっと小さく)したもの。
ssl_error.logエラーの記録。

最初、私は access.log を数えて「75件しかない!?」とびっくりしました。今どきのサイトはほぼhttpsなので、ssl_access.log を見るのが正解です。

ちなみに ssl_access.log-20260922 は、9月22日に切り替わった「9月21日の1日分」のログでした。

手順3:ノートの書き方(形式)を確認する

ログの中身を3行だけ見てみます。

head -3 ssl_access.log-20260922

こんな感じの行が出てきます(IPは例です)。

0.434 BYPASS - 203.0.113.50 - - [21/Sep/2026:00:01:16 +0900] "GET /pc/914.html HTTP/2.0" 200 5661 "-" "Mozilla/5.0 ..." "-"

ここがポイントです。KUSANAGIのログは、ふつうのnginxのログと違って、先頭に「処理にかかった時間」と「キャッシュの状態」が付いています。そのため、ネットでよく見る集計コマンドをそのまま使うとズレてしまいます。

スペースで区切って、左から何番目に何があるかを数えるとこうなります。

番号中身
$1処理時間(秒)0.434
$2・$3キャッシュの状態BYPASS / –
$4来た人のIPアドレス203.0.113.50
$7・$8日時(+0900が別扱いになる)[21/Sep/2026:00:01:16 +0900]
$9やりかた(見る=GET、送る=POST)“GET
$10見たページのURL/pc/914.html
$12門番の返事(ステータス)200

手順4:コマンドでアクセス数を数える

毎回ファイル名を打つのは大変なので、「F」という箱に入れておきます。

F=ssl_access.log-20260922

この箱は、SSHが切れるとからっぽになります。入りなおしたら、cdとこの行をもう一度打ってください。からっぽのまま命令を打つと、画面が止まったように見えます(そのときは Ctrl + C で止めます)。

全部で何回アクセスがあったか

wc -l $F

結果:4,389回(ロボットや画像の読み込みも全部ふくみます)

何人来たか(ロボットを除く)

grep -viE 'bot|crawl|spider' $F | awk '{print $4}' | sort -u | wc -l

結果:481人。名前に bot や spider が付いているロボットを除いて、IPアドレスの種類を数えています。

よく見られたページのランキング

grep -viE 'bot|crawl|spider' $F | awk '$12==200 {print $10}' | grep -vE '\.(css|js|png|jpe?g|gif|webp|svg|ico|woff2?)|^/wp-' | sort | uniq -c | sort -rn | head -20

ロボット・画像・WordPressの管理系を除いて、ちゃんと表示された(200)ページだけを数えています。

すると、ランキングの中に見慣れないものが…

    314 /
     60 //xmlrpc.php
     39 /feed
      7 /xmlrpc.php
      7 /pc/914.html

xmlrpc.php(WordPressの裏口)に、1日で67回もアクセスが来ていました。

手順5:裏口に来たのは誰?

grep 'xmlrpc.php' $F | awk '{print $4}' | sort | uniq -c | sort -rn | head -10
     61 34.61.45.60
      2 162.241.63.88
      1 192.0.112.206
      ...

9月21日の時点で、1つのIPから61回! ちなみに 192.0.112.206 の1回は、WordPress.com(Jetpack)のサーバーのIPです。その日、私はスマホのJetpackアプリで1回サイトを見ていたので、おそらくその分だと思います。自分は1回しか見ていないのに、別のIPから61回来ている…あやしいです。

何をしてきたのか調べる

grep '34.61.45.60' $F | head -3

34.61.45.60 の部分は、手順5で自分のログから見つけた「回数が多いIP」に書きかえてください。このIPは私のサイトに来た攻撃者なので、そのままだと何も表示されません。

わかったことはこちら。

ログに残っていたもの意味
CMS-Checker/1.0「このサイトは何で作られてる?」を調べる道具の名前
Chrome/782019年の古いブラウザのふり。変装の定番です
//wp-includes/wlwmanifest.xmlWordPressにしかないファイル。「WordPressかどうか」の確認

つまり、「何のサイトか調べる」→「WordPressだと確認」→「裏口からログインを試す」という、典型的な自動攻撃ロボットでした。

ログインを試みた? 成功した?

grep '34.61.45.60' $F | grep xmlrpc | awk '{print $9, $12}' | sort | uniq -c
      1 "GET 200
     60 "POST 200

60回「POST(送信)」=ログインを試していました。でも、xmlrpc.phpは、パスワードが間違っていても「200」を返すので、これだけでは成功したかわかりません。そこで「返事の大きさ」を見ます。

grep '34.61.45.60' $F | grep xmlrpc | awk '{print $13}' | sort | uniq -c
     60 508
      1 822

60回ともぴったり同じ508バイト=全部「パスワードがちがいます」という同じ返事です。全部失敗していて一安心。2段階認証も入れていたので、二重に守られていました。

手順6:GoAccessでグラフにする

コマンドの結果は数字だらけで見にくいので、GoAccessというツールでグラフにします。WordPressの管理画面ではなく、サーバーに入れるツールです。

インストール(VPSで打つ)

dnf install -y epel-release
dnf install -y goaccess
goaccess --version

バージョン番号(私は1.11)が出ればOKです。

KUSANAGI用の設定でレポートを作る

手順3で見たとおり、KUSANAGIのログは特別な形なので、--log-format で形を教えてあげます。これが一番大事なポイントです。

cd /home/kusanagi/mypc/log/nginx/
zcat -f ssl_access.log-2026* | LANG=C goaccess - --log-format='%T %^ %^ %h %^ %^ [%d:%t %^] "%r" %s %b "%R" "%u" %^' --date-format='%d/%b/%Y' --time-format='%H:%M:%S' --ignore-crawlers -o /root/report.html
部分意味
zcat -f ssl_access.log-2026*圧縮した過去のログも、今のログも、まとめて読む
LANG=Cログの「Sep」などの英語の月を正しく読ませるおまじない
%T %^ %^ %h処理時間・(無視)・(無視)・IPアドレス、という順番だよ、と教える
–ignore-crawlersロボットを除く
-o /root/report.html結果をHTMLファイルにして保存

最後の -o /root/report.html を消すと、PowerShellの画面の中に直接表示されます(q キーで終了)。

パソコンにダウンロードする(パソコンで打つ)

ここはVPSではなく、自分のパソコンのPowerShell(PS C:\… と出ている画面)で打ちます。VPSの中で打つと「Could not resolve hostname c:」というエラーになります。

scp -P 12345 root@203.0.113.1:/root/report.html C:\Users\あなたのユーザー名\Desktop

ssh はポート指定が小文字の -p でしたが、scp は大文字の -Pです。注意!

デスクトップにできた report.html をダブルクリックすると、ブラウザでグラフ付きのレポートが見られます。

レポートでわかったこと

項目結果(8/1〜9/22)
訪問者数(Unique Visitors)39,218人(1日600〜900人くらい)
リクエスト数のグラフときどき2〜3万回にはね上がる日がある。でも訪問者数は増えていない=攻撃の日

手順7:攻撃の全体を数える

1か月半ぶんで、どこにPOST(送信)が来たかを数えます。

zcat -f ssl_access.log-2026* | awk '$9=="\"POST" {print $10}' | sort | uniq -c | sort -rn | head -10
 126603 /xmlrpc.php
  36949 //xmlrpc.php
   2215 /wp-json/wordpress-popular-posts/v2/views/31
   1863 /wp-login.php

xmlrpc.phpへの送信が約16万3千回。1日平均3,000回ペースでした。

Jetpackの「総当たり攻撃からの保護」はONになっていましたが、これはWordPressが動いた「後」で止める仕組みです。つまり毎日3,000回、WordPress(PHP)がむだに働かされていました。

そこで、玄関の門番(nginx)の時点で追い返すことにしました。

手順8:なぜ裏口を「全部」ふさがないの?

「xmlrpc.phpを全部ブロックすればいいじゃん」と思いますよね。でも、スマホのJetpackアプリは、WordPress.comのサーバーを通って、このxmlrpc.phpでサイトとやりとりしています。全部ふさぐと、アプリでサイトが見られなくなります。

そこで作戦はこうです。

来た人門番の対応
Jetpack(WordPress.com)のサーバーどうぞ(許可)
それ以外の全員お帰りください(403)

許可するIPは、Jetpack公式ページ「How to add Jetpack IPs to an allowlist」に載っているものを使います。このIPは変わることがあるので、ときどき公式ページを確認してください。

手順9:門番(nginx)の設定を書きかえる

設定ファイルの場所

cd /etc/opt/kusanagi/nginx/conf.d/
ls

KUSANAGI 9では、サイトごとに3つのファイルがあります。

ファイル役割
mypc.confメインの設定
mypc.wp.incWordPress用の設定(今回いじるのはここ)
mypc.proxy.incキャッシュ関係

まずはバックアップ

失敗してもすぐ戻せるように、コピーを取っておきます。

cp mypc.wp.inc mypc.wp.inc.bak

中身を確認

grep -n -A3 '^#location ~\* /xmlrpc' mypc.wp.inc
45:#location ~* /xmlrpc.php(/|$) {
46-#    satisfy all;
47-#    deny all;
48-#}

KUSANAGIは、最初からxmlrpc.phpをブロックする設定を用意してくれています。でも、行の頭に # が付いていますね。これは「コメントアウト」といって、門番はこの行をただのメモとして無視します。つまり、今は効いていません。

しかも中身は deny all;(全員おことわり)なので、# を外すだけだとJetpackアプリまで使えなくなります。なので、この4行を「Jetpackだけ許可」版に置きかえます。

新しい設定を別ファイルで作る

エディタ(nano)で編集しようとしたら、キーが反応しなくて大失敗しました。なので、コピペだけでできる方法にしました。次の11行を、まとめて貼り付けてEnterします。

cat > mypc.xmlrpc.inc << 'EOF'
location ~* /xmlrpc.php(/|$) {
    allow 122.248.245.244;
    allow 54.217.201.243;
    allow 54.232.116.4;
    allow 192.0.64.0/18;
    allow 195.234.108.0/22;
    deny all;
    include conf.d/fastcgi.inc;
}
EOF
意味
location ~* /xmlrpc.php「xmlrpc.phpに来た人には、次のルールを使うよ」
allow 〜Jetpackのサーバーは通してOK
deny all;それ以外は全員おことわり
include conf.d/fastcgi.inc;通した人は、ちゃんとWordPressにつなぐ(これがないとJetpackも動きません)

Jetpack公式には 192.0.80.0/20・192.0.96.0/20・192.0.112.0/20 も載っていますが、これらは全部 192.0.64.0/18 の中に入っているので、まとめて1行にしています。

できたか確認します。

cat mypc.xmlrpc.inc

#の4行を「読みこみ」の1行に置きかえる

sed -i '/^#location ~\* \/xmlrpc\.php/,/^#}/c\include conf.d/mypc.xmlrpc.inc;' mypc.wp.inc

#location ~* /xmlrpc.php の行から #} の行までを、include conf.d/mypc.xmlrpc.inc; の1行に置きかえてね」という命令です。

確認します。

grep -n -B2 -A2 'mypc.xmlrpc' mypc.wp.inc
43-}
44-
45:include conf.d/mypc.xmlrpc.inc;
46-
47-location ~ [^/]\.php(/|$) {

45行目に入りました。ふつうのPHPの設定(47行目)よりにあるのが大事です。門番は上から順番にルールを見るからです。

設定にまちがいがないかチェック

ここでつまずきました。nginx -t と打つと「コマンドが見つかりません」。KUSANAGI 9では、nginxが特別な場所に入っています。本当の場所を調べます。

ps aux | grep 'nginx: master'
root  927734 ... nginx: master process /opt/kusanagi/nginx129/sbin/nginx

場所がわかったので、フルパスでチェックします(nginx129の数字はバージョンによって変わります)。

/opt/kusanagi/nginx129/sbin/nginx -t
nginx: the configuration file /etc/opt/kusanagi/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/opt/kusanagi/nginx/nginx.conf test is successful

「syntax is ok」と「test is successful」の2つが出るまで、次に進んではいけません。

反映する

/opt/kusanagi/nginx129/sbin/nginx -s reload

何も表示されずに戻ってくればOK。reload(リロード)はサイトを止めずに設定だけ読みなおすので、見ている人に迷惑はかかりません。

手順10:ちゃんと効いているか確認

curl -s -o /dev/null -w "%{http_code}\n" -X POST https://example.com/xmlrpc.php
curl -s -o /dev/null -w "%{http_code}\n" https://example.com/

example.com は自分のサイトのURLに書きかえてください。

確認したもの結果意味
xmlrpc.php403裏口は門前払い。成功!
トップページ200ふつうのページは今まで通り見られる

最後に、スマホのJetpackアプリでサイトが今まで通り見られるかも確認しました。バッチリ動きました!

ほかのサイトにも同じ設定をする

同じVPSのnandemoとwebcssにも、同じ手順でやりました。中身は同じなので、ファイルをコピーするだけです。

cd /etc/opt/kusanagi/nginx/conf.d/
cp nandemo.wp.inc nandemo.wp.inc.bak
cp webcss.wp.inc webcss.wp.inc.bak
cp mypc.xmlrpc.inc nandemo.xmlrpc.inc
cp mypc.xmlrpc.inc webcss.xmlrpc.inc
sed -i '/^#location ~\* \/xmlrpc\.php/,/^#}/c\include conf.d/nandemo.xmlrpc.inc;' nandemo.wp.inc
sed -i '/^#location ~\* \/xmlrpc\.php/,/^#}/c\include conf.d/webcss.xmlrpc.inc;' webcss.wp.inc
grep -n 'xmlrpc.inc' nandemo.wp.inc webcss.wp.inc
/opt/kusanagi/nginx129/sbin/nginx -t

チェックがOKなら反映します。

/opt/kusanagi/nginx129/sbin/nginx -s reload

curlで確認して、403・200・403・200と出れば完了です。

もしJetpackアプリが動かなくなったら(元に戻す方法)

バックアップを取っておいたので、2行ですぐ元に戻せます。

cp /etc/opt/kusanagi/nginx/conf.d/mypc.wp.inc.bak /etc/opt/kusanagi/nginx/conf.d/mypc.wp.inc
/opt/kusanagi/nginx129/sbin/nginx -s reload

つまずいたポイントまとめ

こまったこと原因解決方法
access.log が見つからないホーム(~)にいたcd でログのフォルダに移動する
アクセスが75件しかないhttp側のログを見ていたssl_access.log を見る
IPが1種類しか出ないKUSANAGIはログの列がずれているIPは$4、URLは$10、ステータスは$12
急に操作できなくなる放っておいてSSHが切れた-o ServerAliveInterval=60 を付けて入りなおす
命令を打つと止まる入りなおして $F がからっぽCtrl + C で止めて、cd と F= をやりなおす
Could not resolve hostname c:scpをVPSの中で打ったexit でパソコンに戻ってから打つ
nanoでキーが反応しない接続切れやキーの横取りcat と sed のコピペ方式にする
nginx: コマンドが見つかりませんKUSANAGI 9は特別な場所にあるps aux で場所を調べてフルパスで打つ

まとめ

PowerShellとGoAccessでアクセス数を調べたら、1日3,000回ペースのログイン攻撃が見つかりました。

  • 2段階認証とJetpackの保護で、ログインは全部失敗していた
  • それでもWordPressがむだに働かされていたので、nginxの時点でブロック
  • Jetpackのサーバーだけ許可したので、スマホアプリはそのまま使える
  • KUSANAGIの「#付きの用意された設定」は、そのままでは効いていない

こういう攻撃は、WordPressサイトならどこでも毎日のように来ています。「自分のサイトは小さいから大丈夫」ではなく、一度ログをのぞいてみることをおすすめします。

気になる中古パソコン

パソコン

Supported by Rakuten Web Service

コメント

タイトルとURLをコピーしました
PR

当サイトは、Amazon、楽天アソシエイト・他プログラムの参加者です。リンクを通じて商品を購入すると、紹介料を得る場合があります。

⚠ 免責事項

本記事は、筆者が実際に行った作業を記録したものです。サーバーの環境や設定によっては、同じ手順でも結果が異なる場合があります。

作業を行う際は、事前にバックアップを取ったうえで、ご自身の責任で実施してください。本記事の内容を参考にしたことによって生じたトラブルや損害について、当サイトは一切の責任を負いかねますので、あらかじめご了承ください。