【ITニュース解説】I built a PHP2Shell checker the morning the patch dropped. Here's what 650 checks showed
2026年10月22日に「Dev.to」が公開したITニュース「I built a PHP2Shell checker the morning the patch dropped. Here's what 650 checks showed」について初心者にもわかりやすく解説しています。
ITニュース概要
PHPにログイン不要でリモートコード実行が可能な重大な脆弱性「PHP2Shell」が見つかった。公式パッチはPHP 8.2~8.5のみで、8.1以前は提供されず危険な状態だ。多くのサイトが古いバージョンを使用しており、自身のPHPバージョン確認と、修正版への更新・再起動が急務である。
ITニュース解説
PHPというプログラミング言語に、非常に深刻な二つの脆弱性(セキュリティ上の欠陥)が発見され、緊急の対応が求められた。これらは「PHP2Shell」と名付けられ、具体的にはCVE-2026-109618とCVE-2026-109619という識別番号がつけられている。この脆弱性の最大の問題点は、攻撃者がログインすることなく、遠隔地からサーバー上で任意のコード(プログラム)を実行できてしまう、という点だ。もしこれが悪用されれば、ウェブサイトが改ざんされたり、個人情報が盗まれたり、サーバーが乗っ取られたりする可能性があり、非常に危険な事態を引き起こす。
この脆弱性の詳細がパッチ(修正プログラム)が公開される前日にインターネット上に漏れてしまい、すぐにこの脆弱性を悪用するプログラムが出回り始めた。そのため、パッチが公開された時点で、すでにオランダやフィンランドの政府系サイトが攻撃を受け、一時的にサービスが停止するなどの被害が発生していた。これは、ソフトウェアの脆弱性がどれほど迅速に悪用されるかを示す、恐ろしい例だ。
さらに深刻な問題として、PHPのバージョンによってパッチの提供状況に大きな差があったことが挙げられる。公式に修正プログラムが提供されたのはPHP 8.2から8.5の比較的新しいバージョンのみだった。具体的には8.2.35、8.3.36、8.4.27、8.5.12というバージョンがリリースされた。しかし、PHP 8.1やそれより古いバージョンを使っているサイトには、公式な修正プログラムは提供されなかった。これらの古いバージョンを使っている人々は、PHPのソースコードを自分で修正してビルドし直すか、最新バージョンにアップグレードするしかない。多くの小規模ビジネスサイトや、安価な共有ホスティングサービスを利用しているサイトは、コストや手間を理由に、このような古いPHPバージョンを使い続けていることが多い。そして、そのサイトの管理者自身が、自分のサイトが脆弱な状態にあることを知らないというケースが非常に多い。
このような現状に危機感を覚えた筆者は、パッチ公開からわずか1時間で、自分のサイトが脆弱なPHPバージョンを使っているかどうかをチェックできる無料ツール「simgen.dev/php-patch-check」を開発し、公開した。このツールは、ウェブサイトの公開情報のみを読み取り、脆弱性自体を直接探るような危険な動作は一切行わない。具体的には、HTTPヘッダーの「X-Powered-By: PHP/8.1.2」のような情報や、PHPSESSID、laravel_session、wordpress_*といったクッキー、あるいはWordPressの/feed/にあるジェネレータタグなどから、そのサイトがPHPを使っているかどうか、そしてもし可能であればそのバージョンを推測する。
初日のデータによると、チェックされた658サイトのうち、PHPが使われていると確認できたのは310サイトだった。その中でも、PHPのバージョン情報を公開している85サイトのうち30サイトが、すでにサポートが終了した(EOL: End-of-Life)バージョンを使用していた。これは、公式なアップデートが今後一切提供されない、極めて危険な状態にあることを意味する。データは自己選択されたサンプルではあるが、検出された傾向は、PHPサイトの約半分がもはやパッチを受け取れないバージョンで動作しているという専門機関の推定とも一致している。最も多く使われていたシステムはWordPressで、次にLaravel、Matomoが続いた。
このチェッカーツールを開発する過程でもいくつかの課題に直面した。Node.jsという開発環境の標準的な通信機能(fetch)が、古いApacheサーバーと通信しようとすると、一部の特別なヘッダー(Connection: Upgrade)のせいで応答を待ち続けてしまう問題があった。脆弱なサイトほど古いサーバーを使っていることが多いため、この問題は致命的だった。そこで筆者は、Node.jsが提供するより低レベルな通信機能(node:httpとnode:https)を直接使い、タイムアウトや受け取るデータ量の上限を自分で設定することでこの問題を回避した。
また、任意のURLをチェックできるツールは、SSRF(Server-Side Request Forgery)という、攻撃者が意図しない内部サーバーにアクセスさせる脆弱性を悪用されるリスクがある。このリスクを避けるため、チェッカーは、通信プロトコルをHTTPとHTTPSに限定し、アクセスするポート番号も制限した。さらに、サイトのドメインが解決されたIPアドレスがプライベートネットワークやループバックアドレス、クラウドのメタデータアドレスなど、外部からアクセスされるべきではないアドレスではないかを厳重にチェックした。これにより、DNSの仕組みを悪用した攻撃(DNSリバインディング)も防ぐ対策が講じられた。古いサイトは応答が遅いことが多く、20秒から30秒もかかるサイトもあったため、ユーザーがツールの進行状況を分かりやすく見られるように、UI(ユーザーインターフェース)の工夫も行われた。
多くのサイトはセキュリティ上の理由からPHPのバージョン情報を外部に公開していない。そのため、外部からのチェックだけでは正確なバージョンが特定できない場合がある。そこで、バージョンが隠されている場合のために、ユーザーが自身のサーバーにアップロードして実行できる小さなPHPスクリプト「check-php.php」が提供された。このスクリプトは、実行するとPHPのバージョン情報とそのバージョンがEOLであるかどうかを表示し、その後すぐに自分自身をサーバーから削除する。これにより、ユーザーは自分のPHPバージョンを外部に公開することなく、正確な情報を知ることができ、かつこのスクリプト自体がサーバーに残り続けることもない。このスクリプトが生成するリンクをユーザーがクリックしてチェッカーに戻ると、筆者には匿名の形で実際のバージョン情報が集計される仕組みも作られている。
パッチを適用する際に多くの人が見落としがちな非常に重要な点がある。それは、修正プログラムをサーバーにインストールしただけでは、実行中のPHPプロセスはまだ古い脆弱なコードを使い続けている、ということだ。ウェブサーバーでPHPを動かす仕組みであるPHP-FPMやApacheのmod_phpなどは、サーバーが再起動されるまで、古いバイナリ(プログラムの実体)をメモリ上に保持し続ける。そのため、パッチを適用した後は、必ずPHP関連のサービスを再起動する必要がある。さらに、cPanelやPleskのようなホスティング管理パネルを使用しているサーバーでは、複数のPHPバージョン(例えばPHP 7.4、8.1、8.2など)が並行してインストールされていることがよくある。この場合、それぞれのPHPバージョンに対して個別にパッチを適用し、それぞれのサービスを再起動しなければならない。
このような複雑な状況に対応するため、筆者はサーバーにインストールされているすべてのPHPの状態をチェックし、古いバイナリでまだ実行中のPHP-FPMプロセスがないかを発見するシェルスクリプト「check-all-php.sh」も作成した。これは、実行中のプロセスの情報と、PHPのバイナリがいつ更新されたかを比較することで、再起動が必要なPHPプロセスを特定できる。
また、現代の開発ではCI/CD(継続的インテグレーション/継続的デプロイ)という自動化された開発フローが一般的だ。しかし、この環境下でもPHPの脆弱性が修正されないまま残ってしまうことがある。ComposerというPHPの依存関係管理ツールはPHP自体のバージョンを直接管理しないため、composer updateを実行してもPHP2Shellの脆弱性は修正されない。古いバージョンのPHPは、Dockerコンテナのベースイメージ、composer.json内のconfig.platform.php設定、.php-versionファイル、またはCI/CDの設定でPHPのバージョンを指定する場所などに、隠れて残ってしまうことがある。そこで筆者は、これらの見落としがちな場所をすべてチェックし、プルリクエスト内で問題箇所を具体的に指摘してくれるGitHub Action「KyleClouthier/php2shell-action@v1」も作成し、公開している。
この脆弱性に関する情報が広まる中で、いくつかの誤解も多く見られた。「WordPressを更新したから大丈夫」という考えは間違いだ。この脆弱性はWordPressではなく、その下で動いているPHP自体にあるため、WordPressの自動更新では修正されない。「session.upload_progressをオフにした」という対策も、攻撃経路の一つを塞ぐだけであり、PHPの公式情報によると完全な修正にはならない。「Cloudflareの背後にいるから安全」という意見も、Cloudflare自体が提供するルールは一時的な防御に過ぎず、根本的な解決ではないと明言している。「サイトのバージョンを隠しているから攻撃されない」というのも誤解で、攻撃者はまずバージョンを確認するのではなく、攻撃を仕掛けてみて脆弱性があるかどうかを試すことが多い。「mod_phpだけが影響を受ける」という話も間違いで、PHP-FPMやphp-cgi、FrankenPHP、LiteSpeedなど、他のPHP実行環境も同様に影響を受ける。mod_phpは最も典型的な例に過ぎない。
サイト管理者やこれからシステムエンジニアを目指す初心者にとって、最も重要なアドバイスは以下の通りだ。まず、自分のウェブサイトで動いているPHPの正確なバージョンを確認すること。もしPHP 8.2から8.5の範囲であれば、必ず最新の修正版(例:8.2.35など)が適用されているかを確認し、PHPが正しく再起動されていることを確かめる必要がある。もしPHP 8.1以前の古いバージョンを使っている場合は、ホスティングサービスプロバイダに、この脆弱性に対する修正(バックポートと呼ばれる古いバージョンへの修正適用)が行われているかを文書で問い合わせるべきだ。そして、将来的な安全のためにも、PHP 8.2以降の新しいバージョンへの移行を計画することが強く推奨される。新しいバージョンへの移行は、古いプラグインやテーマが動作しなくなる可能性があるため、必ず本番環境に適用する前に、テスト環境(ステージングコピー)で十分に動作確認を行うことが重要だ。最後に、脆弱な状態にあった期間中に、ウェブサイトに心当たりのない新しい管理者ユーザーが作成されたり、不審なファイルがアップロードされたり、ファイルが不自然に更新されたりしていないかを念入りに確認することも忘れてはならない。
これらの対策を徹底することが、ウェブサイトを安全に保つための第一歩となる。