PHP2Shell、AIが見つけたPHPの穴 修正版は8.5.12

古い岩肌のモノクロ写真 AI

PHP の本体に、細工した HTTP リクエスト1つで外からコードを動かせる穴が2つ見つかりました。見つけたのはセキュリティ企業 Calif の研究者で、LLM と組み合わせた調査を始めてから2日で最初のバグに行き着いています。修正版の PHP 8.2.35・8.3.36・8.4.27・8.5.12 は10月21日に出ました。11月2日には IEEE Spectrum がThe PHP2Shell Vulnerability Heralds Cybersecurity Hell という記事で、AI のせいで40年分の技術的負債を払わされていると書き、Hacker News では1,237ポイント・721件のコメントがつきました。WordPress や Laravel で作ったサイトも対象なので、手元の PHP の版と設定を確かめる手順もまとめます。

背景と文脈

PHP2Shell は、CVE-2026-109618 と CVE-2026-109619 の2つの穴をまとめた呼び名です。名前をつけたのは Calif で、GitHub の勧告ではどちらも CVSS v4.0(穴の深刻さを10点満点で表す共通の尺度)で9.2点がついています。php.net によると、PHP-FPM、Apache の mod_php、php-cgi、FrankenPHP、LiteSpeed など、Web で PHP を動かす形はすべて対象です。

穴の一部は、ずっと前から残っていました。Calif の解説によると、もっとも古い経路は PHP 5.4.0 のころのコードです。メモリ不足のときの不具合は2020年のバグ報告 #78876 で一度指摘され、2024年の外部監査(OSTIF と Quarkslab)でも見つかっていました。ただ、そのときは攻撃に使えるところまでは示されていません。

今年の7月30日、Calif は OpenAI の Patch the Planet という取り組みに招かれ、PHP の調査を始めました。8月1日に最初のバグを見つけ、8月14日には攻撃の試作コード(PoC:穴が本当に使えることを示す短いコード)を PHP 側に渡しています。同じ根っこの問題は、OpenAI の Codex Security と、クラウドセキュリティ企業の Wiz もそれぞれ別に報告しました。3者がほぼ同じ時期に、同じ穴にたどり着いています。

公開までには混乱もありました。PHP Foundation の説明では、公開予定の前日に CVE の番号と誤った深刻度(10.0)が外に漏れました。Calif も試作コードを見せる動画を誤って公開しています。PHP Foundation は、公開の時点で実際に動く攻撃コードは確認していないとしています。

技術/ビジネス面

白い壁の横にある緑の木の扉
Photo by Pawel Czerwinski on Unsplash

1つ目の CVE-2026-109618 は、メモリが足りなくなったときの処理の穴です。PHP はメモリの確保に失敗すると、処理の途中から一気に抜け出します。このとき、リクエストのデータが作りかけのまま後片付けが走り、壊れたデータを読んでしまいます。Calif の説明では、POST の本文やアップロードされたファイルを PHP が自動で読みこむ部分から、この状態に持ちこめます。

2つ目の CVE-2026-109619 は、前のリクエストのデータが残ってしまう穴です。エラーやセッションの情報が、メモリを解放したあとも参照できるまま残ります。同じワーカーで次に動くリクエストが、初期化の前にそれを使ってしまうしくみです。確認された経路には、初期設定で有効な session.upload_progress.enabled(アップロードの進み具合をセッションに記録する機能)と、PHP 8.5 で入った fatal_error_backtraces があります。

Calif は、WordPress 7.1.2、Drupal 11.4.3、Laravel 13.11、phpMyAdmin 5.2.3、Nextcloud 35.0.1 などで、ログインなしでコードを動かせたと書いています。ただし、どの環境でも同じように通るわけではありません。GitHub の勧告 GHSA-w8hw-w9fx-j79w は、1つ目の穴について PHP-FPM での完全な攻撃はまだ示されていないとしています。PHP Foundation は、アプリ側の処理を通せば FPM でも動いたと書いていて、情報源によって書き方に差があります。

IEEE Spectrum の記事が心配しているのは、同じことがこの先もくり返される点です。コロンビア大学の Suman Jana 氏は、穴を見つけるほうが直すよりずっと楽になったと話しています。PHP2Shell でも、最初の報告(8月11日)から修正版の公開(10月21日)まで2か月以上かかりました。ジョンズ・ホプキンス大学の Matthew Green 氏は、2027年の早いうちに「本当にまずいこと」が起きるかもしれないと見ています。

開発者として試すなら

最初にするのは、Web サーバーで動いている PHP の版を確かめることです。コマンドラインの php と Web 側の PHP は、別の版や別の php.ini を使っていることがあります。コマンドラインでは次のように見られます。

php -v
php -i | grep -E "memory_limit|post_max_size|session.upload_progress.enabled"

Web 側の値は、phpinfo() を呼ぶページを一時的に置いて見るのが確実です。見終わったら、そのページは必ず消します。直った版は次のとおりです。

系列 直った版 補足
8.5 8.5.12 Windows 版は Brotli の修正込みの 8.5.12-1
8.4 8.4.27 Windows 版は 8.4.27-1
8.3 8.3.36 Windows 版は 8.3.36-1
8.2 8.2.35 2026年12月31日でサポート終了
8.1 以前 なし PHP プロジェクトからの更新はなく、7.4・8.0・8.1 向けの最小限の修正ブランチだけ

Linux ならディストリビューションのパッケージに修正が入ったかを確かめ、Docker なら公式イメージのタグを上げて作り直します。php.net、Calif、PHP Foundation の3つとも、完全に防げるのは更新だけだとしています。

すぐに更新できないときのつなぎとして、php.net と GitHub の勧告は次の設定をあげています。

  • php.ini か FPM のプールの設定に session.upload_progress.enabled=0 を書く(ini_set() や .user.ini では効きません)
  • PHP 8.5 では fatal_error_backtraces=0 にする
  • php_admin_value で memory_limit=-1 に固定する(これだけでは防げないと勧告にあります)
  • アップロードを使わないアプリは post_max_size を 8M、使うなら 32M にし、upload_max_filesize はそれより小さくする
  • リバースプロキシで、本文の大きさ・項目の数・ヘッダーの数に上限をつける
  • 設定を変えたら、すべてのワーカーを再起動する

エラーの表示を止めても、この穴は防げません。勧告には、error_reporting や display_errors、@ でエラーを隠しても効果がないと書かれています。レンタルサーバーの場合は、PHP の版をコントロールパネルで選ぶところが多くあります。古い系列を選んだままになっていないか、パネルで見ておくと安心です。

これからどうなるか

PHP の穴そのものは更新で直ります。IEEE の記事と Hacker News の議論が気にしているのは、その先です。Hacker News のスレッドで一番長く続いたのは、形式検証(コードが仕様どおりに動くことを数学で証明するやり方)で、バグのないソフトが作れるのかという話でした。dbingham さんは、証明は数学ではうまくいっても現実のソフトでは難しく、バグを減らせるかはテストにかける費用と責任のとり方で決まると書いています。AnthonyMouse さんは、LLM で穴を探す費用は下がり続けているのに、AI が書き足すコードは誰も確かめていないと指摘しました。

開発者の手元で変わるのは、更新を待てる期間の長さです。PHP2Shell では、報告から公開までの2か月半のあいだに番号の流出や動画の誤公開が起きました。古いランタイムを動いているからと残しておくと、次に AI で見つかった穴が出たとき、修正版のない状態で公開日を迎えます。8.2 は12月31日でサポートが終わるので、8.2 のサイトは今回の更新とあわせて 8.3 以降へ移す日も決めておくと、次の穴では修正版を入れるだけで済みます。

まとめ

PHP2Shell は、Web で PHP を動かす形すべてに関わる2つの穴で、10月21日の 8.2.35・8.3.36・8.4.27・8.5.12 で直りました。まず Web 側の PHP の版を確かめ、すぐに上げられないときは session.upload_progress.enabled=0 などの設定でしのぎます。AI で古いコードの穴が見つかる速さは上がっているので、12月でサポートが切れる 8.2 は早めに移しておきます。

参考リンク

アイキャッチ画像: Photo by Leo_Visions on Unsplash

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