OpenAIのphp2shell-checkerは、最初の切り分けには役立ちます。ただし、これだけでサーバーの安全性を証明できるわけではありません。HTTPヘッダーやphp -vから取得したPHPバージョンを、組み込まれた修正版の基準と比較する仕組みなので、バージョンヘッダーが隠されていればUNKNOWNになります。一方、ディストリビューション側で修正がバックポートされていると、実際には対策済みのサーバーが脆弱と判定されることもあります。
まずは結果コードの意味を押さえる
OpenAI公式リポジトリが返す重要な状態は3つあります。いずれも包括的な脆弱性診断の結果ではなく、あくまで初動調査の手がかりとして扱ってください。
| 出力 | 終了コード | 分かること | 次に行うこと |
|---|---|---|---|
OK | 0 | 認識されたブランチで、検出バージョンが最低修正版以上 | Webトラフィックを処理しているPHPプロセスも同じバージョンか確認する |
VULNERABLE | 1 | 検出バージョンが最低修正版を下回っている | Webサービスが使うランタイムを更新し、ワーカーを再起動してから両方のチェックを再実行する |
UNKNOWN | 3 | 認識可能なバージョンまたはレスポンスを確認できなかった | サーバー上で調査する。対策済みとは判断しない |
| 引数が不正 | 2 | コマンド自体が正しくない | コマンドを修正して再実行する |
OpenAIが公開したもの
公開されているphp2shell-checkerリポジトリには、Node.jsスクリプト、テスト、そして2つのCodexスキルが含まれています。外部から到達できるサイト向けのphpcheck-urlと、アクセス権のあるサーバー向けのphpcheck-serverです。このツールが調べるのはバージョン情報であり、対象への攻撃やアプリケーションコードのスキャンではありません。
環境に合った方法でチェックする
公開URLを調べる
まずリポジトリをクローンまたはダウンロードし、Node.jsスクリプトにサイトのURLを渡して実行します。
node phpcheck.js "https://example.com"
リモートチェックはHTTPのHEADリクエストを送り、サーバーが405または501を返した場合に限ってGETへフォールバックします。確認するのはX-Powered-ByとServerで、リダイレクトには追従せず、レスポンス本文も調べません。
CDNやリバースプロキシ、expose_php=off、独自のサーバー設定によって、レスポンスがチェッカーへ届く前にPHPのバージョン情報が削除されることがあります。VULNERABLEならパッチ適用が必要ですが、ヘッダーがない場合はサーバー上の情報で確認しなければなりません。
ローカルのPHPバイナリを調べる
PHPがインストールされたマシンでは、次のコマンドを使います。
node phpcheck.js --local
これは現在のPATHから見つかるバイナリに対してphp -vを実行します。ただし、そのバイナリがWebサイトの処理にも使われているとは限りません。同じホストに、CLI、PHP-FPM、CGI、Apacheモジュール、コンテナ、ソースからビルドした環境が別々に存在することもあります。
ローカルチェックの後は、Webサーバーにつながっている実際のランタイムを特定してください。コンテナ環境なら、イメージタグだけでなく稼働中のコンテナを確認します。パッケージで導入したサービスなら、該当するPHP-FPMプールまたはApacheモジュールと、ベンダーのパッケージ変更履歴を調べます。
Codexスキルをインストールして使う
公式READMEでは、2つのスキルを1つのCodexコマンドでインストールします。
$skill-installer install both skills from https://github.com/openai/php2shell-checker
続いて、アクセスできる対象に合ったインターフェースを選びます。
$phpcheck-url check https://example.com
$phpcheck-server check the PHP version serving my site
Codexの利用は任意です。CIジョブや最小構成のホストでは、Node.jsコマンドを直接使えます。自動化する場合は--jsonを追加してください。patch_statusフィールドがok、vulnerable、unknownを返すため、スクリプトでターミナルの文章を解析する必要がありません。
ダウンロードしたチェッカーを検証する
このリポジトリでは、Node.js組み込みのテストランナーを使います。
node --test phpcheck.test.js
テストスイートは、ローカルのHTTPサーバーに対するCLIの動作と、ローカル環境のシナリオ用に用意された偽のPHP実行ファイルを検証します。READMEによれば、実際のPHPのインストールも外部サイトへのアクセスも必要ありません。
UNKNOWNはデバッグ結果として読む
UNKNOWNは、情報が足りていないという意味で扱ってください。対象がPHPのバージョンを隠している、認識されないブランチを使っている、応答に失敗している、あるいは新しいプレリリース版を動かしている可能性があります。いずれの場合も、修正が適用済みだとは判断できません。
実際のユーザーである@jvr0xは、この制限を次のように説明しています。
「Oct 20の基準値とバージョンを比較しているだけなので、ヘッダーが隠されているとUNKNOWNになります」
リモートコマンドが見ているのはHTTPレスポンスであり、リバースプロキシの背後にあるプロセスではありません。ヘッダーが隠されている場合は、URLへの再試行ではなくサーバー側のチェックが必要です。
UNKNOWNが出たら、次の順番で確認します。
- サイトを提供しているホスト上で
node phpcheck.js --localを実行する。 - リクエストがPHP-FPM、CGI、Apacheの
mod_php、またはコンテナのどれに届いているか特定する。 - ベンダーのパッケージ変更履歴を確認し、修正がバックポートされていないか調べる。
- 更新後、該当するPHP-FPMまたはApacheのワーカーを再起動する。
- シェルのデフォルト
phpバイナリだけでなく、実際にリクエストを受ける経路から検証する。
SSHアクセスがなければ、URLモードが最初にできる唯一の確認になる場合もあります。共有ホスティングでバージョンヘッダーが抑制されているなら、提供元に実際のランタイム、パッケージのリビジョン、再起動状況を確認してもらう必要があります。
バージョン表だけでパッチ適用の可否は決められない
このチェッカーでは、各ブランチの最低修正版としてPHP 8.5.12、8.4.27、8.3.36、8.2.35を扱います。公式テストでは8.4.26がVULNERABLE、8.4.27がOKと確認されています。また、PHPは8.5.12、8.4.27、8.3.36、8.2.35をセキュリティリリースとして案内しています。
| ブランチ | 最低修正版のアップストリームリリース | 脆弱と判定される直前のリリース |
|---|---|---|
| PHP 8.5 | 8.5.12 | 8.5.11 |
| PHP 8.4 | 8.4.27 | 8.4.26 |
| PHP 8.3 | 8.3.36 | 8.3.35 |
| PHP 8.2 | 8.2.35 | 8.2.34 |
| デプロイ状況 | 単純なバージョン比較が誤解を招く理由 | 確認に使う情報 |
|---|---|---|
X-Powered-ByまたはServerヘッダーが隠されている | リモートチェッカーがPHPを特定できない | ローカルのランタイム情報 |
| DebianまたはUbuntuのセキュリティパッケージ | ベンダーが古いアップストリームのバージョン文字列のまま修正をバックポートしている可能性がある | ベンダーのアドバイザリとパッケージ変更履歴 |
| 1台のホストでPHP-FPMとCLIを併用 | php -vがHTTPワーカーではなくCLIの情報を示している可能性がある | WebサーバーとFPMの設定 |
| キャッシュされたコンテナまたは固定されたダイジェスト | レジストリのタグが新しくても、稼働中のコンテナは古いままの可能性がある | 稼働中のコンテナのイメージIDとバージョン |
| ApacheまたはFPMのワーカーを再起動していない | ディスク上のファイルは修正済みでも、古いワーカーが動き続けている可能性がある | プロセスの起動時刻と再起動後のチェック |
| サポート対象外のブランチまたはプレリリース版 | チェッカーがベンダー固有の修正状況を認識できない可能性がある | PHPまたはベンダーのセキュリティ告知 |
リポジトリの制限事項には、一覧に含まれるブランチでは後続の安定版パッチに修正が含まれると仮定しており、実際に修正が入っているかを独自に検証することはできないと記載されています。ディストリビューションがアップストリームのバージョン番号を変えずにセキュリティ修正をバックポートすることもあるため、表示された番号だけでなく変更履歴のほうが強い根拠になる場合があります。
WordPress、Drupal、LaravelなどのPHPアプリケーションを更新しても、PHPエンジン自体にはパッチが適用されません。ランタイムのパッケージまたはイメージを更新し、ワーカーを再起動したうえで、Webリクエストを受け付けるプロセスを確認してください。
FAQ
本番環境の対応チケットを完了にできる結果はどれですか?
どの結果も、それだけでチケットを完了にすべきではありません。OKに加えて、実際に使われているSAPI、ベンダーによるバックポートの有無、関係するすべてのvhostまたはコンテナ、パッチ適用後にワーカーが再起動されたことまで確認してください。