アクセスログの「200 0」は危険?WordPressで不審なPHPアクセスを調査した記録 | UNIX Cafe

* 当サイトでは、コンテンツの一部に広告を掲載しています。

System Note $ cat /proc/ai-disclosure

本記事の構成および論理分析にはAI(人工知能)を使用しています。情報の正確性は、システム管理者(UNIXユーザー)による手動検証済みです。

アクセスログの「200 0」は危険?WordPressで不審なPHPアクセスを調査した記録 | UNIX Cafe

WordPressサイトのアクセスログを確認していたところ、存在しないはずのPHPファイルに対して 200 が大量に返っているログを見つけました。

最初に見た集計は次のようなものでした。

20.79.29.209 | 154回 | [200:137回] [301:8回] [404:7回] [403:2回]
CRITICAL paths: /env.php,/environment.php,/sql.php,/wp-content/plugins/hellopress/wp_filemanager.php

/env.php/sql.php200 が返っていると、かなり不安になります。設定ファイルやデータベース関連のファイルを探す典型的なスキャンだからです。

お?! と思って調べてみた結果、今回のログは実ファイルに対しての「侵入成功」ではありませんでした。理由は、200 の後ろにあるレスポンスサイズがすべて 0 だったためです。

目次

ログの見方

アクセスログの1行は、例えば次のような形です。

example.com 20.79.29.209 - - [28/Jul/2026:06:24:16 +0900] "GET /sql.php HTTP/1.1" 200 0 "-" "-"

重要なのはこの部分です。

"GET /sql.php HTTP/1.1" 200 0

この部分は、こういう意味です。

/sql.php へアクセスされた
HTTPステータスは 200
レスポンス本文サイズは 0バイト

通常、ページやファイルの中身を返している場合は、最後のサイズが 0 ではなく、数百から数万バイトになります。

こんな形です。

"GET /some-page/ HTTP/2.0" 200 39524

この場合は 39524 バイトの本文を返しています。

一方、今回の怪しいアクセスは次のように 200 0 でした。

"GET /environment.php HTTP/1.1" 200 0
"GET /env.php HTTP/1.1" 200 0
"GET /sql.php HTTP/1.1" 200 0
"GET /wp-content/shell.php HTTP/1.1" 200 0

つまり、ログ上は 200 ですが、本文は返していません。

サーバーを確認する

まず、サーバーにSSHで接続し、攻撃対象にされたファイルが実在するかどうかを確認しましす。

find . \( -name 'env.php' -o -name 'environment.php' -o -name 'sql.php' -o -name 'wso*.php' -o -name 'c99.php' \)

結果は何も表示されませんでした。

さらに、特に気になったパスも確認します。

find . \( -path '*/wp-content/shell.php' -o -name 'phpinfo.php' -o -name 'configuration.php' \)

これも何も表示されませんでした。

次に、uploads/ 配下にPHPファイルが置かれていないかも確認します。

cd /home/example/example.com/public_html/wp/wp-content/uploads
find . -type f \( -name '*.php' -o -name '*.phtml' -o -name '*.phar' \)

こちらも該当ファイルはありませんでした。

この時点で、少なくとも現在のファイルシステム上には、攻撃者が探していたPHPファイルは存在しないことが確認できています。

なぜ200なのに被害がなかったのか

200 だけを見ると、ファイルが存在して正常に返されたように見えます。

しかし今回のログでは、怪しいPHPアクセスの多くが 200 0 でした。

これは「HTTPステータスとしては200だが、本文を返していない」という状態です。Xserverやnginx、Apache、rewrite、WAF、セキュリティ設定、クライアント側の切断などの影響で、403ではなく、空の200として記録されるケースがあります。

そのため、今回は次のように判断しました。

200 0       = 警戒対象。ただし情報漏えいやPHP実行の証拠とは断定しない
200 大きい値 = 実際に本文を返している可能性が高い
403         = 拒否されている
404         = 存在しない

今回のケースでは、危険パスに 200 が出ていたものの、本文サイズは 0 で、実ファイルも見つかりませんでした。

そのため、「侵入成功」ではなく「攻撃スキャンを受け、サーバー側で空の200として記録された可能性が高い」という判断になりました。

実施した対策

まず、該当IPを .htaccess でブロックしました。

Require not ip 20.79.29.209

ただし、今回のIPはMicrosoft Azure系のレンジでしたので、クラウドIPからのスキャンは、別IPに変わって再発することがあります。IP単体のブロックだけでは不十分ですので.htaccessに次の内容を追記します。

これで、探索されやすい危険パスを明示的に 403 Forbidden にすることができます。

# Block common probe paths
RewriteRule "(^|/)(?:\.env(?:\..*)?|env\.php|environment\.php|sql\.php|phpinfo\.php|info\.php)$" - [F,L,NC]
RewriteRule "(^|/)wp-content/plugins/(?:hellopress/wp_filemanager\.php|fix/up\.php)$" - [F,L,NC]
RewriteRule "(^|/)(?:wp-admin/install\.php|wp-admin/maint/|wordpress/wp-admin/maint/)" - [F,L,NC]

さらに、wp-content/uploads 配下でもPHPが実行されないようにします。

サーバーにSSHでログインしているので、そのままwp-content/uploads/ディレクトリに移動して、vi .htaccessで新規ファイルを作成し、.htaccess に次の内容を貼り付けて保存します。

<FilesMatch "\.(php|phtml|phar|php[0-9]*)$">
Require all denied
</FilesMatch>

WordPressの通常運用では、uploads 配下でPHPを実行する必要がないからです。

対策後の確認作業

セキュリティ設定を変更した後は、必ず実機で確認作業を行います。ログに残っていた全ての実在しないファイルを指定して、 403 が返ってくることを確認します。

curl -I https://example.com/env.php
curl -I https://example.com/environment.php
curl -I https://example.com/sql.php
curl -I https://example.com/wp-content/plugins/hellopress/wp_filemanager.php
curl -I https://example.com/wp-content/plugins/fix/up.php

期待する結果は 403 Forbidden です。

今回の環境では、すべて期待通り 403 が返ってきました。

/env.php                                      403
/environment.php                              403
/sql.php                                      403
/wp-content/plugins/hellopress/wp_filemanager.php 403
/wp-content/plugins/fix/up.php                403

生ログで200のPHPアクセスを見るコマンド

自分の管理IPを除外して、PHPの 200 を探すには、次のスクリプトを実行しました。

awk '$2!="自分の管理IP" && $0 ~ /"(GET|POST) .*\.php/ && $0 ~ /" 200 / {
  print $2, $8
}' example.com.access_log_20260727 example.com.access_log_20260728 \
| sort | uniq -c | sort -nr \
| awk '{printf "%5d  %-15s  %s\n", $1, $2, $3}'

ログ形式によりますが、今回のログでは $2 がIPアドレス、$8 がアクセスされたパスでした。

まとめ

今回のケースでは、200 だけで判断しないことがポイントでした。

200 が返っている
しかしレスポンスサイズは 0
実ファイルは存在しない
uploads配下にもPHPファイルはない

この条件がそろっていたため、今回は侵入成功の証拠は見つかっていないと判断しました。

また、現在は403化できていることから、次回以降の対策もできていることを確認して作業を終了しました。

ただし、/env.php/sql.php を探すアクセスは明確に攻撃スキャンですので、200 0 が紛らわしい場合は、危険パスを .htaccess やWAFで明示的に 403 にしておく方が安全です。

ログ調査では、ステータスコードだけでなく、レスポンスサイズと実ファイルの存在確認まで行うことが大事だということが分かりました。

Linux学習におすすめの本|コマンド・シェルスクリプト・サーバーまで

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

のいのアバター のい UNIX Cafe マスター

Macintosh Color Classicから始まった旅は、長いWindows時代を経て、Windows10のサポート終了をきっかけにUNIXの世界へ戻ってきました。UNIX Cafeでは、UNIX・Linux・そしてMacな世界を、むずかしい言葉を使わず、物語のように書いています。プログラミングは、アイデアをコンピューターに伝えるための言葉です。簡単な単語と文法を覚えれば、誰でもコマンドを使えます。ぜひ一度、やさしいプログラミングの世界をのぞいてみてください。

目次