こんにちは、インフラエンジニアのryuです。
前回の記事「PHPの緊急脆弱性「php2shell」とは?」では、2026年10月21日に公開されたPHPの脆弱性の仕組みと、アップデートの進め方を解説しました。
今回はその続きです。
アップデートを終えたあとに、多くの人が気になるのが「すでに攻撃されていないか?」という点だと思います。
実際に、Datadog Security Labsの解説記事によると、10月21日の時点で悪用の報告が複数あり、公開の4日前にあたる10月17日には攻撃の試みが観測されていたとされています。
つまり、修正版を入れた日より前に、攻撃を受けていた可能性があるということです。
PHPをアップデートしても、すでに置かれた不正なファイルや、起動された不正なプログラムは消えません。この記事では、サーバーに残る痕跡をどこで、どう確認するかを整理します。
調べる期間を決めておく¶
調査を始める前に、まず「いつからいつまでのログを見るか」を決めます。
今回は、公開の4日前にあたる10月17日には攻撃の試みが観測されています。そのため、少なくとも10月17日から、自分のサーバーでPHPのアップデートが完了した時刻までが調査の対象になります。
| 時期 | 状態 | 調査の必要性 |
|---|---|---|
| 10月17日より前 | 攻撃の報告なし | 余裕があれば確認 |
| 10月17日〜アップデート完了まで | 攻撃を受けた可能性がある | 重点的に確認 |
| アップデート完了後 | 新たな攻撃は防げている | 侵入済みの場合の不審な動きを確認 |
ここで困るのが、ログが残っていないケースです。ログローテーションの設定によっては、1週間ほどで古いログが削除されてしまいます。
# ローテーションされた古いログが残っているか確認する
ls -l /var/log/nginx/ /var/log/apache2/
調査が終わるまでは、ログを別の場所へコピーして保管しておくと安心です。
攻撃の痕跡は「3つの場所」で探す¶
php2shellの攻撃を調べるときは、次の3つの場所を見ます。
| 確認する場所 | 見るもの | 主な確認先 |
|---|---|---|
| ① 受け取ったHTTPリクエスト | 異常に大きいフォーム送信 | アクセスログ、WAF、リバースプロキシ |
| ② PHPのエラーログ | メモリ不足のエラー、ワーカーの異常終了 | PHP-FPMやApacheのエラーログ |
| ③ Webサーバーが起動したプロセス | Webサーバーの子プロセスとして動くシェル | ps、監視ツール、EDR |
大切なのは、1つの痕跡だけで「攻撃された」「攻撃されていない」と判断しないことです。
例えばメモリ不足のエラーは、普段の大きなアップロードでも起きます。反対に、攻撃が成功した場合でも、エラーが出ずに正常な応答(HTTP 200)が返ることがあります。
3つの場所の記録を、時刻を合わせて突き合わせることが調査の基本になります。
① 不審なフォーム送信がないか確認する¶
攻撃リクエストの特徴¶
Datadogが検証した攻撃では、普通のWebフォームと同じ形式(application/x-www-form-urlencoded)のPOSTリクエストが使われていました。
見た目はただのフォーム送信ですが、中身には次のような特徴があります。
- 約3.5MBもある、異常に長いフィールド名が含まれる
- 名前が空のフィールドに、制御文字(ヌルバイトなど)を含むバイナリデータが入っている
ログインフォームのような通常の入力欄で、数MBの項目名が送られてくることはまずありません。
アクセスログで大きなPOSTを探す¶
まずは、Webサーバーのアクセスログから、PHPへのPOSTリクエストを確認します。
# POSTリクエストの多い送信元IPを数える(Nginxの例)
sudo grep '"POST ' /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head
標準的なログ形式では、リクエストの大きさ(ボディのサイズ)は記録されません。Nginxなら$request_length、Apacheならmod_logioの%Iをログ形式に加えておくと、受け取ったバイト数を残せます。
今回のような事態に備えて、普段からリクエストサイズを記録しておくと、あとの調査がずっと楽になります。
WAFやリバースプロキシでの対策¶
WAF(Web Application Firewall)やリバースプロキシを使っている場合は、次のようなリクエストを検知・遮断するルールを検討します。
- フォームのフィールド名が異常に長い
- フォームの値に、想定しない制御文字が含まれる
制限値は、自分のアプリケーションの正常な通信を基準に決めます。いきなり厳しくすると、正規のアップロードまで止めてしまうからです。
WAFが大きなリクエストを途中までしか検査しない設定になっていると、検査されなかった部分に攻撃の中身があっても見逃します。WAFの検査上限と、アプリケーションが受け付ける上限が合っているかも確認しましょう。
② PHPのエラーログを確認する¶
「Unknown on line 0」のメモリ不足エラー¶
攻撃の試行では、PHPのエラーログに次のような致命的エラーが記録されていました。
PHP Fatal error: Allowed memory size of 16777216 bytes exhausted
(tried to allocate 3500032 bytes) in Unknown on line 0
注目したいのはUnknown on line 0の部分です。
通常のメモリ不足なら、どのPHPファイルの何行目で起きたかが記録されます。Unknown on line 0は、スクリプトが動き出す前、リクエストを受け取って準備している途中でメモリが足りなくなったことを示しています。
ログは次のように検索できます。
# PHP-FPMのログから探す(パスは環境に合わせて変更)
sudo grep -n "Unknown on line 0" /var/log/php*-fpm.log
# Apache(mod_php)の場合はエラーログに出る
sudo grep -n "Allowed memory size" /var/log/apache2/error.log
ログの保存場所が分からない場合は、Apacheのログの保存場所や、PHP-FPMの設定ファイル(error_logの項目)を確認してください。
ワーカーの異常終了¶
攻撃者がメモリの位置を推測し損ねると、Webサーバーのワーカーが異常終了することがあります。Apacheでは次のようなログが残ります。
AH00052: child pid ... exit signal Segmentation fault (11)
sudo grep -n "Segmentation fault" /var/log/apache2/error.log
Segmentation faultは、プログラムが不正なメモリにアクセスして強制終了したことを表します。
NginxとPHP-FPMの構成では、ワーカーの異常終了はPHP-FPMのログに記録されます。あわせて、Nginxのエラーログに上流(PHP-FPM)との接続が切れた記録が残ることもあります。
# PHP-FPMのワーカーがシグナルで終了した記録
sudo grep -n "exited on signal" /var/log/php*-fpm.log
# Nginx側で上流との接続が途中で切れた記録
sudo grep -n "upstream prematurely closed" /var/log/nginx/error.log
どちらも、普段から一定数は出ることがあるログです。件数が急に増えた日時がないかに注目すると、いつもとの違いに気づきやすくなります。
これらのエラーが、①の大きなPOSTリクエストや、上流の接続リセットと同じ時刻に集中していないかを確認します。
ただし、メモリ不足もワーカーの異常終了も、正当な処理で起きることがあります。それだけで攻撃と断定はできません。
CVE-2026-109619で見るポイント¶
もう1つの脆弱性(CVE-2026-109619)については、外部からアクセスできるURLで、次のようなログが増えていないかを確認します。
- 起動直後の設定に関する警告
- 終了処理(シャットダウン)中の診断メッセージ
- 致命的なエラー
- 実行時間の上限超え(タイムアウト)
PHPの公式アドバイザリでは、こうしたイベントが、前のリクエストの内部状態が残ってしまう経路と関係している可能性が示されています。
③ Webサーバーが起動したプロセスを確認する¶
もっとも直接的な証拠は「シェルの起動」¶
3つの中で、攻撃の成功をもっとも直接的に示すのが、Webサーバーのワーカーがシェルを起動しているという痕跡です。
Datadogの検証では、Apacheのワーカーがシェルを起動し、そのシェルが攻撃者のサーバーへ外向きの通信を張っていました。
apache2 (www-data)
└── sh -c <リバースシェルのコマンド>
└── bash [外部サーバーへの通信]
本来、WebサーバーはHTTPリクエストを処理するだけで、シェルを起動する必要はほとんどありません。
Linuxで確認するコマンド¶
まず、Webサーバーの実行ユーザー(Ubuntuならwww-data、RHEL系ならapacheやnginx)が動かしているプロセスを確認します。
# プロセスの親子関係をツリーで表示する
ps -ef --forest | less
# www-data が実行しているプロセスだけを見る
ps -u www-data -o pid,ppid,lstart,cmd
apache2やphp-fpmの下に、shやbash、見覚えのないプログラムがぶら下がっていないかを確認します。
あわせて、外部への通信も確認します。
# 確立している通信と、それを持つプロセスを表示する
sudo ss -tnp state established
Webサーバーの実行ユーザーのプロセスが、見覚えのない外部のIPアドレスへ接続している場合は要注意です。
「普段の動き」を知っておく¶
アプリケーションによっては、画像変換などのために、意図して外部コマンドを実行するものもあります。
そのため、普段どんなプロセスが起動しているか(ベースライン)を把握しておくことが大切です。普段の動きが分かっていれば、いつもと違う動きにすぐ気づけます。
攻撃の検知を、特定のコマンド名やHTTPのステータスコード、ワーカーの異常終了に頼らないようにしてください。改良された攻撃では、リクエストは正常な応答を返し、ワーカーも動き続けます。
不審なファイルや自動実行の設定も確認する¶
攻撃者がシェルを手に入れると、次にアクセスするための仕掛けを残すことがあります。代表的なのは、Webから実行できる不正なPHPファイル(Webシェル)や、定期的に動く不正なプログラムです。
ドキュメントルートの中で、調査期間に新しく作られたり変更されたりしたファイルを探します。
# 10月17日以降に変更されたPHPファイルを探す(パスは環境に合わせて変更)
sudo find /var/www -type f -name '*.php' -newermt '2026-10-17' -ls
# 一時ディレクトリに置かれた実行ファイルも確認する
sudo find /tmp /var/tmp /dev/shm -type f -newermt '2026-10-17' -ls
デプロイやプラグインの更新でも変更日時は新しくなるため、見つかったファイルが自分たちの作業によるものかを照らし合わせます。
あわせて、Webサーバーの実行ユーザーに定期実行の設定が追加されていないかも確認します。
sudo crontab -u www-data -l
ls -l /etc/cron.d/
普段は空のはずのwww-dataのcrontabに設定が入っていたら、強く疑うべき痕跡です。
このほか、/etc/passwdへの見覚えのないユーザーの追加や、~/.ssh/authorized_keysへの不明な公開鍵の追加も、攻撃者が再び入るための手口としてよく使われます。Webサーバーの実行ユーザーの権限だけでは書き換えられないファイルですが、権限昇格まで進まれていないかを確かめる意味で、念のため確認しておきましょう。
痕跡が見つかったらどうする?¶
痕跡が見つかった場合や、判断に迷う場合は、次の順番で対応します。
| 順番 | やること | 注意点 |
|---|---|---|
| 1 | ログとシステムの状態を保存する | 再起動や削除の前に保存する |
| 2 | サーバーを隔離する | 外部への通信を止め、被害の拡大を防ぐ |
| 3 | セキュリティ担当者へ報告する | 一人で判断しない |
| 4 | 認証情報を変更する | DBのパスワード、APIキー、クラウドの認証情報など |
| 5 | 修正済みの環境で作り直す | 不正なファイルが残っている前提で考える |
特に気をつけたいのは、慌ててサーバーを再起動したり、怪しいファイルを消したりしないことです。メモリ上の情報や証拠となるファイルが失われ、何が起きたのかを調べられなくなります。
また、PHPの実行ユーザーが読めるファイルに、データベースの接続情報やクラウドの認証情報が書かれていた場合は、それらが盗まれた前提で変更しておく必要があります。
日頃のログ確認の方法は「Linuxのログ監視」でも紹介しています。
InfraAcademyでログ調査の基礎を身につけよう¶
今回紹介したgrepやps、ssのコマンド、ログの保存場所、プロセスの親子関係は、どれもLinuxの基本です。
ただ、いざ緊急事態になってから調べ始めると、「どのログを見ればいいのか」「この出力は正常なのか」が分からず、時間がかかってしまいます。
InfraAcademyでは、ブラウザ上でLinuxのコマンドを実行しながら、ログの確認やプロセスの管理を練習できます。学ぶ順番はLinuxの学習ロードマップにまとめています。
また、攻撃の流れや痕跡の調べ方を基礎から学びたい方には、セキュリティ入門講座がおすすめです。Webアプリケーションの脆弱性やシステムへの侵入の手口に加えて、防御・検知・インシデント対応までを、演習環境で手を動かしながら学べます。攻撃者がどう動くかを知っておくと、今回のような痕跡の調査でも「何を探せばいいか」が自然に分かるようになります。
まとめ¶
php2shellの攻撃の痕跡を調べるときのポイントを振り返ります。
- 公開前から攻撃の試みが観測されており、アップデート前に攻撃されていた可能性がある
- 痕跡は「リクエスト」「エラーログ」「プロセス」の3つの場所で探す
Unknown on line 0のメモリ不足エラーや、ワーカーの異常終了は手がかりになる- もっとも直接的な証拠は、Webサーバーのワーカーが起動したシェル
- 1つの痕跡だけで判断せず、時刻を合わせて突き合わせる
- 痕跡が見つかったら、再起動や削除の前に証拠を保存し、担当者と連携する
アップデートで終わりにせず、「すでに入られていないか」まで確認してはじめて対応が完了します。まずは自分のサーバーのエラーログを、Unknown on line 0で検索するところから始めてみましょう。
参考資料¶
本記事は、2026年10月23日時点の公開情報をもとに作成しています。



